Compiling OpenCV with CUDA

Alex Punnen
Better ML
Published in
9 min readNov 16, 2017

OpenCV is the most popular and widely used Computer Vision libraries with a host of algorithms. Many of these algorithms have GPU accelerated versions based on the equally popular NVIDIA CUDA libarary. If you are starting Computer Vision projects using Deep learning or Machine Learning you will come across the need to install OpenCV with CUDA as you may need to use OpenCV GStreamer or FFMPEG based libraries to decode the video into image frames or resize the images and create the image matrix data structure cv::Mat or cv::cuda::GpuMat for futher processing by Tensorflow.

There are basically two ways to go about this.

Easiest way is to build inside a Docker container and use that container for your development; Yes you can export also the GUI using X11

OR Build in your machine.

For both you need a laptop or server with a NVDIA GPU and preferably a stable Ubuntu version; The below should work in other Linux versions changing the package manager commands.

Step 1. Install NVIDIA Driver

Never ever install directly from NVIDIAs .run file as there is a high chance that it mess with the display — lightdm and causes instability.(So unless you are an OS expert, please don’t; or if you are brave enough, try basically installing without opengl option --no-opengl-file ); and if you still mess with display there are enough threads to help you)

Simpler way

sudo apt-get install build-essential
sudo apt-add-repository ppa:graphics-drivers/ppa
sudo apt-get update
sudo apt-get install nvidia-3xx
sudo modeporbe nvidia (also ran this before restart)

Please see detailed instruction here

https://medium.com/techlogs/install-the-right-nvidia-driver-for-cuda-in-ubuntu-2d9ade437dec

Check — Step 1 : Check install status via nvidia-smi command

+ — — — — — — — — — — —— — — — — — — — — — — — — — -+
| NVIDIA-SMI 375.39 Driver Version: 375.39 |
| — — — — — — — — — — — — — + — — — — — — — — — — — +
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|================+======================+======================|
| 0 GeForce GT 720M Off | 0000:01:00.0 N/A | N/A |
| N/A 51C P0 N/A / N/A | 271MiB / 1985MiB | N/A Default |
+ — — — — -+ — — — — — — — — — — — + — — — — — — — — — — — +

There are two options now; one is to install CUDA in your machine and then compile OpenCV. The other simpler option is to use nvidia-cuda docker container and install OpenCV in that.

Step 2: Using nvidia-cuda Docker Container and install OpenCV in it

Download OpenCV 3.4 source and un zip it; Example I put it in my home folder.

Do docker volume mapping with nvidia-cuda docker container.

docker run --net=host --runtime=nvidia -it -v /home/alex/coding:/coding  nvidia/cuda /bin/bash

Install OpenCV relevant packages in the container; only these are needed. Not that this is to compile OpenCV with FFMPEG. The -dev versions are needed for compilation. You don’t however need this for build. You can use the Docker multi-stage build to create a build directory from this dev.

apt-get -y update
apt-get install -y cmake pkg-config \
zlib1g-dev ffmpeg libwebp-dev \
libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev \
libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev

If you want to export display from the Docker image install X packages also

apt-get install x11-apps 

Create a directory named ‘build’ and cd to that. Run cmake with the following options. Change CUDA_TOOLKIT_ROOT_DIR and CUDA_ARCH_BIN=6.0 6.1 7.0 appropriately.

cmake -D CMAKE_BUILD_TYPE=Release -D BUILD_PNG=OFF -D BUILD_TIFF=OFF -D BUILD_TBB=OFF -D BUILD_JPEG=OFF -D BUILD_JASPER=OFF -D BUILD_ZLIB=OFF -D BUILD_EXAMPLES=OFF -D BUILD_opencv_java=OFF -D BUILD_opencv_python2=ON -D BUILD_opencv_python3=OFF -D ENABLE_NEON=ON -D WITH_OPENCL=OFF -D WITH_OPENMP=OFF -D WITH_FFMPEG=ON -D WITH_GSTREAMER=OFF -D WITH_GSTREAMER_0_10=OFF -D WITH_CUDA=ON -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-9.0 -D WITH_GTK=ON -D WITH_VTK=OFF -D WITH_TBB=ON -D WITH_1394=OFF -D WITH_OPENEXR=OFF -D CUDA_ARCH_BIN=6.0 6.1 7.0 -D CUDA_ARCH_PTX="" -D INSTALL_C_EXAMPLES=OFF -D INSTALL_TESTS=OFF ..

Make sure that it has detected CUDA ; Note the CUDA_TOOLKIT_ROOT_DIR path. This should change with different CUDA versios

CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-9.0

After this make install

make install

This should install OpenCV with headers in the Docker container. Now quit the container without killing it-https://stackoverflow.com/questions/25267372/correct-way-to-detach-from-a-container-without-stopping-it

Ctrl+p, Ctrl+q

Save the container

docker ps (and see the commit id of the container you just paused and exited say c1d0beb84729)docker commit  -m "with opencv3.4" c1d0beb84729  alexcpn/nvidia-cuda9-opencv34:1.0

You can docker attach and kill the previous container.

Here is the Dockerfile for the same, if you just need OpenCV and no other tools for dev. Not that in the below file I am compiling OpenCV with GStreamer instead of FFMPEG as shown above.

FROM nvidia/cuda# This is a dev image, needed to compile OpenCV with CUDA# Install  Gstreamer and OpenCV Pre-requisite libsRUN  apt-get update -y && apt-get install -y \
libgstreamer1.0-0 \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-libav \
gstreamer1.0-doc \
gstreamer1.0-tools \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev
RUN apt-get update -y && apt-get install -y pkg-config \
zlib1g-dev libwebp-dev \
libtbb2 libtbb-dev \
libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev \
cmake
RUN apt-get install -y \
autoconf \
autotools-dev \
build-essential \
gcc \
git
ENV OPENCV_RELEASE_TAG 3.4.5RUN git clone https://github.com/opencv/opencv.git /var/local/git/opencv
RUN cd /var/local/git/opencv && \
git checkout tags/${OPENCV_RELEASE_TAG}
RUN mkdir -p /var/local/git/opencv/build && \
cd /var/local/git/opencv/build $$ && \
cmake -D CMAKE_BUILD_TYPE=Release -D BUILD_PNG=OFF -D \
BUILD_TIFF=OFF -D BUILD_TBB=OFF -D BUILD_JPEG=ON \
-D BUILD_JASPER=OFF -D BUILD_ZLIB=ON -D BUILD_EXAMPLES=OFF \
-D BUILD_opencv_java=OFF -D BUILD_opencv_python2=ON \
-D BUILD_opencv_python3=OFF -D ENABLE_NEON=OFF -D WITH_OPENCL=OFF \
-D WITH_OPENMP=OFF -D WITH_FFMPEG=OFF -D WITH_GSTREAMER=ON -D WITH_GSTREAMER_0_10=OFF \
-D WITH_CUDA=ON -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ -D WITH_GTK=ON \
-D WITH_VTK=OFF -D WITH_TBB=ON -D WITH_1394=OFF -D WITH_OPENEXR=OFF \
-D CUDA_ARCH_BIN=6.0 6.1 7.0 -D CUDA_ARCH_PTX="" -D INSTALL_C_EXAMPLES=OFF -D INSTALL_TESTS=OFF ..
RUN cd /var/local/git/opencv/build && \
make install
# Install other tools you need for development

Note that we are using nvidia/cuda which is a fat image and is needed for the build. But nvidia/cuda-runtime can be used for runtime.

Now you can do docker volume mapping and work inside this Docker image for compiling and other development activities.

docker run --net=host --runtime=nvidia -it -v /home/alex/coding:/coding  dockerimagename

If you need to have display; You can run the following command first in the host.

sudo xhost +
--output --> access control disabled, clients can connect from any host

And then run the container.

docker run --net=host --env DISPLAY=unix$DISPLAY --privileged --volume $XAUTH:/root/.Xauthority --volume /tmp/.X11-unix:/tmp/.X11-unix  --rm --runtime=nvidia --rm -it -v /home/alex/coding:/coding  alexcpn/nvidia-cuda-grpc:1.1 bash

If you need to Dockerise your application; you can create a much leaner image than the development image above. For that you can use Docker mutli-stage build concept to create a runtime Docker container.

FROM  alexcpn/cuda9-grpc-opencv34-gstreamer:latest as buildFROM nvidia/cuda:9.0-runtime# Copy the compiled libs of OpenCV, GRPC and Protobuf from buildCOPY --from=build /usr/lib/lib* /usr/local/lib/
COPY --from=build /usr/local/lib/* /usr/local/lib/
COPY --from=build /usr/local/include/* /usr/local/include/
COPY --from=build /usr/lib/x86_64-linux-gnu/ /usr/lib/x86_64-linux-gnu/
# Install GStreamer related libs - just copying libs wont help wih h264 decode
RUN apt-get update -y && apt-get install -y \
libgstreamer1.0-0 \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-libav
RUN apt-get install -y gstreamer1.0-tools
# Do the rest what you need

The other option of compiling OpenCV with CUDA is to install CUDA in your machine and install OpenCV

Download and install CUDA, currently CUDA 8, but without installing the drivers; There is a --driver=no option in command line; But follow the installation dialog and prompt no when asked.

Check the installation via nvccc --version

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2016 NVIDIA Corporation
Built on Tue_Jan_10_13:22:03_CST_2017
Cuda compilation tools, release 8.0, V8.0.61

Note :- If you get a perl5 missing error in Ubuntu 17 , please see this https://devtalk.nvidia.com/default/topic/968656/cuda-8-0-on-debian/

Now on-to compiling OpenCV with CUDA; Most of the CNN based frameworks use OpenCV for image pre-processing; OpenCV also uses ffmpeg/gstreamer and some other libraries in the back-end; so step 1 here is 3. -Install all pre-requisites

sudo apt-get -y update 
sudo apt-get -y upgrade
sudo apt-get -y autoremove
sudo apt-get install -y cmake pkg-config \
zlib1g-dev ffmpeg libwebp-dev \
libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev \
libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev

4. Then Download OpenCV; I used OpenCV 3.0 and OpenCV 3.3.0 and also OpenCV 3.4.

There are two option also here; One configure CMake graphically using cmake-gui listed below; or use a command line to configure

Install via CMake command line

mkdir build inside opencv** extracted folder. Set the CUDA Path and Lib path in case CMake complains like

OpenCV is not able to find/configure CUDA SDK (required by WITH_CUDA).CUDA support will be disabled in OpenCV build.

cd build
sudo ldconfig /usr/local/cuda/lib64 or say for running darknet
export PATH=$PATH:/usr/local/cuda/bin
export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64
cmake -D CMAKE_BUILD_TYPE=Release -D BUILD_PNG=OFF -D BUILD_TIFF=OFF -D BUILD_TBB=OFF -D BUILD_JPEG=OFF -D BUILD_JASPER=OFF -D BUILD_ZLIB=OFF -D BUILD_EXAMPLES=OFF -D BUILD_opencv_java=OFF -D BUILD_opencv_python2=ON -D BUILD_opencv_python3=OFF -D ENABLE_NEON=ON -D WITH_OPENCL=OFF -D WITH_OPENMP=OFF -D WITH_FFMPEG=ON -D WITH_GSTREAMER=OFF -D WITH_GSTREAMER_0_10=OFF -D WITH_CUDA=ON -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-8.0 -D WITH_GTK=ON -D WITH_VTK=OFF -D WITH_TBB=ON -D WITH_1394=OFF -D WITH_OPENEXR=OFF -D CUDA_ARCH_BIN=6.0 6.1 7.0 -D CUDA_ARCH_PTX="" -D INSTALL_C_EXAMPLES=OFF -D INSTALL_TESTS=OFF .. -DCUDA_CUDART_LIBRARY=/usr/local/cuda/lib64/libcudart.so

If all dependencies are present cmake configuration will be successful and you should be able to make opencv. Not the options marked in bold. Change for your CUDA version and also only the needed CUDA_ARC_BIN. It will make compilation go much faster

sudo make install

That’s it.

In the beginning it may be easier for you to see all the OpenCV options via a GUI tools. You can configure CMake options graphically via CMake GUI. Follow the steps below

Install via CMake-GUI

mkdir build inside opencv** extracted folder

cd build
cmake ..

This will create intial CMakeCache.txt and also the make file; Now we do not need a lot of libraries and architectures; So removing unwanted and limiting the rest, we can reduce the compile time significantly.

Easy to do via cmake-gui

sudo apt-get install cmake-qt-gui

Change these configuration, by running cmake-gui in the build folder

cmake-gui

Note the CUDA_ARCH_BIN selected by default CMake, You need to set the architecture for only the architecture that your card supports -https://developer.nvidia.com/cuda-gpus#collapse4

You can see that for GTX 1070 it supports compute capability 6.1 and from the same source there is a hyperlink to the card Architecure — it is Pascal here

Default Settings

Setting just the needed CUDA_ARCH_BIN and CUDA_GENERATION will speed up the compile time

Set Correct Architecture

If you are using CUDA, you don’t need OpenCL; Actually very few CNN libs (if any, maybe some from Intel) use OpenCL now; Also you do not need OpenBLAS, CUDA has a BLAS library

Check the WITH configurations, we need CUDA, we also need ffmpeg and other libs for working with pictures of different formats , videos etc

When this is done Run Configureand if there are no errors run Generate to gernerate the Make file

Now run sudo make install Compilation takes about half an hour on my Core i7 machine;

P.S- If after installing tensorflow-gpu , you are getting errors regarding Cuda lib linkage please run sudo ldconfig /usr/local/cuda/lib64 or say for running darknet

export PATH=$PATH:/usr/local/cuda/bin
export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64

That’s it. The preferred method now is the first. Use nvidia-docker for building OpenCV inside Docker container and use Docker volume mapping for development.

--

--

Alex Punnen
Better ML

SW Architect/programmer- in various languages and technologies from 2001 to now. https://www.linkedin.com/in/alexpunnen/