OpenCV with C++ and CUDA

February 3, 2024

First install opencv. On arch linux, you may also need to install vtk, glew, and fmt. You also need qt6-base, hdf5, and possibly more! Scan the output of ld the see what dependencies are missing. To compile and link a program:

g++ main.cpp `pkg-config --cflags opencv4` \
    `pkg-config --libs opencv4` 

For a first program, let's display an 8-bit monochrome image of white noise:

#include <iostream>
#include <vector>
#include <random>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
 
using namespace cv;
using random_bytes_engine = 
    std::independent_bits_engine<std::default_random_engine, 
                                 UINT8_WIDTH, unsigned char>;
 
int main()
{
    int ImgSize = 512 * 512 * 1;
    
 
    random_bytes_engine rbe;
    std::vector<unsigned char> data(ImgSize);
    std::generate(begin(data), end(data), std::ref(rbe));
    
    Mat image = Mat(512, 512, CV_8UC1, 
                    reinterpret_cast<unsigned char*>(data.data()));
 
    imshow("Display window", image); 
    waitKey(0);
    return 0;
}

OpenCV's imshow() displays the image in a GUI window: opencv imshow() Note that the controls above allow us to pan, zoom, save, and copy the image to the clipboard.

Building CPU and CUDA code with Make

To integrate OpenCV with CUDA code, we could use the nvcc compiler and pass the same options as before:

nvcc main.cu `pkg-config --cflags opencv4` `pkg-config --libs opencv4`

But since we also have a large amount of CPU only code, the proper way to develop here is to compile the CUDA code with nvcc into a library:

nvcc -c cuda_code.cu

This will generate cuda_code.o, which we can then link using g++:

g++ -o program `pkg-config --cflags opencv4` `pkg-config \
    --libs opencv4 cuda cudart` cuda_code.o main.cpp  

To streamline the build process, use Make. Create a file named makefile:

all: program
 
program: cuda_code.o
    g++ -o program `pkg-config --cflags opencv4` `pkg-config \
        --libs opencv4 cuda cudart` cuda_code.o main.cpp -I.
 
cuda_code.o:
    nvcc -c cuda_code.cu
 
clean:
    rm -f *.o program
 

The indentation in the makefile must be done with tabs, and every line must have an end of line character. So make sure to convert spaces to tabs in your text editor. Also note the -I. flag which tells g++ to look in the current directory.

CMake

Building with Make is a platform specific process. To generalize our build instructions to multiple platforms, we can use CMake.

cmake_minimum_required(VERSION 3.28.0)
set(PROJECT_NAME project.out)
project(${PROJECT_NAME}
	VERSION 1.0 
	LANGUAGES CXX)
 
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS ON)
 
find_package(OpenCV REQUIRED)
 
add_executable(${PROJECT_NAME} main.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ./)	
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})