Table of Contents

  1. Finding OpenCV
  2. Selecting Modules
  3. CUDA Acceleration
  4. opencv_contrib Integration
  5. Building from Source
  6. OpenCV with ONNX Runtime
  7. Cross-Platform Considerations
Back to CMake Mastery Series

OpenCV

June 4, 2026 Wasil Zafar 10 min read

Integrate OpenCV — the world's most popular computer vision library — with CMake for image processing, video analysis, and deep learning inference.

Vision

Finding OpenCV

OpenCV ships CMake config files with every installation, making discovery straightforward. The library exports a single package with selectable components:

# Basic OpenCV discovery
cmake_minimum_required(VERSION 3.20)
project(VisionApp LANGUAGES CXX)

find_package(OpenCV REQUIRED COMPONENTS core imgproc highgui dnn)

add_executable(vision_app main.cpp)
target_link_libraries(vision_app PRIVATE ${OpenCV_LIBS})

# Print version and modules found
message(STATUS "OpenCV version: ${OpenCV_VERSION}")
message(STATUS "OpenCV libraries: ${OpenCV_LIBS}")
message(STATUS "OpenCV include path: ${OpenCV_INCLUDE_DIRS}")

If OpenCV is installed to a custom location:

# Point CMake to OpenCV's config directory
set(OpenCV_DIR "/opt/opencv-4.9/lib/cmake/opencv4" CACHE PATH "OpenCV cmake config")

# Or use CMAKE_PREFIX_PATH
list(APPEND CMAKE_PREFIX_PATH "/opt/opencv-4.9")

find_package(OpenCV 4.5 REQUIRED)
Key Insight: OpenCV provides both legacy variables (${OpenCV_LIBS}) and modern imported targets (opencv_core, opencv_imgproc). For new projects, prefer the imported targets for proper transitive dependency handling.
# Using imported targets (OpenCV 4.x modern approach)
find_package(OpenCV REQUIRED COMPONENTS core imgproc highgui)

add_executable(processor main.cpp)
target_link_libraries(processor PRIVATE
    opencv_core
    opencv_imgproc
    opencv_highgui
)

Selecting Modules

OpenCV is modular — only link what you need to minimize binary size and build times:

# Common module groupings by use case
find_package(OpenCV REQUIRED COMPONENTS
    # Core functionality
    core            # Mat, basic operations, memory management
    imgproc         # Filtering, transforms, color conversion

    # I/O and display
    imgcodecs       # Image file reading/writing (PNG, JPEG, etc.)
    highgui         # Window management, trackbars, mouse events
    videoio         # Video capture and writing

    # Computer vision
    features2d      # Feature detection (ORB, SIFT, AKAZE)
    calib3d         # Camera calibration, stereo, 3D reconstruction
    objdetect       # Cascade classifiers, HOG

    # Deep learning
    dnn             # Neural network inference (ONNX, TensorFlow, Caffe)
)

add_executable(detector detector.cpp)
target_link_libraries(detector PRIVATE ${OpenCV_LIBS})
// detector.cpp — OpenCV module usage example
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>

int main() {
    // Load an image
    cv::Mat image = cv::imread("input.jpg");
    if (image.empty()) {
        std::cerr << "Failed to load image\n";
        return 1;
    }

    // Convert to grayscale (imgproc)
    cv::Mat gray;
    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

    // Apply Gaussian blur (imgproc)
    cv::Mat blurred;
    cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 1.5);

    // Edge detection (imgproc)
    cv::Mat edges;
    cv::Canny(blurred, edges, 50, 150);

    // Display result (highgui)
    cv::imshow("Edges", edges);
    cv::waitKey(0);

    return 0;
}

CUDA Acceleration

OpenCV's CUDA modules provide GPU-accelerated versions of many imgproc and video functions:

# OpenCV with CUDA support
cmake_minimum_required(VERSION 3.20)
project(GpuVision LANGUAGES CXX CUDA)

find_package(OpenCV REQUIRED COMPONENTS
    core imgproc highgui
    cudaimgproc cudafilters cudawarping cudaarithm
)

# Check if OpenCV was built with CUDA
if(NOT OpenCV_CUDA_VERSION)
    message(FATAL_ERROR "OpenCV was not built with CUDA support")
endif()
message(STATUS "OpenCV CUDA version: ${OpenCV_CUDA_VERSION}")

add_executable(gpu_vision gpu_processor.cpp)
target_link_libraries(gpu_vision PRIVATE ${OpenCV_LIBS})
// gpu_processor.cpp — CUDA-accelerated OpenCV
#include <opencv2/core.hpp>
#include <opencv2/core/cuda.hpp>
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/cudafilters.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

int main() {
    // Check CUDA device availability
    int cuda_devices = cv::cuda::getCudaEnabledDeviceCount();
    if (cuda_devices == 0) {
        std::cerr << "No CUDA devices found\n";
        return 1;
    }
    std::cout << "CUDA devices: " << cuda_devices << "\n";

    cv::Mat host_image = cv::imread("input.jpg");
    cv::cuda::GpuMat gpu_image, gpu_gray, gpu_blurred;

    // Upload to GPU
    gpu_image.upload(host_image);

    // GPU color conversion
    cv::cuda::cvtColor(gpu_image, gpu_gray, cv::COLOR_BGR2GRAY);

    // GPU Gaussian blur
    auto filter = cv::cuda::createGaussianFilter(
        CV_8UC1, CV_8UC1, cv::Size(5, 5), 1.5);
    filter->apply(gpu_gray, gpu_blurred);

    // Download result back to CPU
    cv::Mat result;
    gpu_blurred.download(result);

    cv::imshow("GPU Result", result);
    cv::waitKey(0);
    return 0;
}

opencv_contrib Integration

The opencv_contrib repository provides extra modules (ArUco markers, text detection, tracking, etc.) not included in the main distribution. These must be built from source:

# Clone both repositories
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git

cd opencv
git checkout 4.9.0
cd ../opencv_contrib
git checkout 4.9.0

# Build with contrib modules
cd ../opencv
mkdir build && cd build

cmake .. -G Ninja \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/opt/opencv-4.9 \
    -DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
    -DBUILD_EXAMPLES=OFF \
    -DBUILD_TESTS=OFF \
    -DWITH_CUDA=ON \
    -DCUDA_ARCH_BIN="8.6" \
    -DOPENCV_DNN_CUDA=ON

cmake --build . --parallel 8
cmake --install .
# Using contrib modules in your project
find_package(OpenCV REQUIRED COMPONENTS
    core imgproc
    aruco           # ArUco marker detection (contrib)
    xfeatures2d     # SURF, BRIEF descriptors (contrib)
    tracking        # Object tracking algorithms (contrib)
    text            # Text detection/recognition (contrib)
)

add_executable(aruco_app aruco_detect.cpp)
target_link_libraries(aruco_app PRIVATE ${OpenCV_LIBS})

Building from Source

Building OpenCV from source gives you full control over enabled modules, optimizations, and third-party integrations:

# Superbuild pattern for OpenCV
include(ExternalProject)

ExternalProject_Add(opencv_build
    GIT_REPOSITORY https://github.com/opencv/opencv.git
    GIT_TAG 4.9.0
    GIT_SHALLOW ON
    CMAKE_ARGS
        -DCMAKE_BUILD_TYPE=Release
        -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
        -DBUILD_LIST=core,imgproc,highgui,dnn,imgcodecs,videoio
        -DBUILD_SHARED_LIBS=ON
        -DBUILD_TESTS=OFF
        -DBUILD_PERF_TESTS=OFF
        -DBUILD_EXAMPLES=OFF
        -DWITH_FFMPEG=ON
        -DWITH_TBB=ON
        -DWITH_OPENMP=ON
        -DOPENCV_GENERATE_PKGCONFIG=ON
    BUILD_COMMAND cmake --build <BINARY_DIR> --parallel 8
)
BUILD_LIST: The BUILD_LIST CMake variable restricts which modules OpenCV builds. This dramatically reduces compile time — a full OpenCV build can take 30+ minutes, while a focused build with 5-6 modules finishes in under 5 minutes.

OpenCV with ONNX Runtime

OpenCV's DNN module can load ONNX models directly for inference, but for maximum performance you may want to combine OpenCV preprocessing with ONNX Runtime inference:

# OpenCV + ONNX Runtime side by side
cmake_minimum_required(VERSION 3.20)
project(InferenceApp LANGUAGES CXX)

find_package(OpenCV REQUIRED COMPONENTS core imgproc dnn)
find_package(onnxruntime REQUIRED)

add_executable(inference inference.cpp)
target_link_libraries(inference PRIVATE
    ${OpenCV_LIBS}
    onnxruntime::onnxruntime
)
// inference.cpp — OpenCV preprocessing + DNN inference
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>

int main() {
    // Load ONNX model via OpenCV DNN
    cv::dnn::Net net = cv::dnn::readNetFromONNX("model.onnx");

    // Select backend (CUDA if available)
    net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
    net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);

    // Preprocess input image
    cv::Mat image = cv::imread("input.jpg");
    cv::Mat blob = cv::dnn::blobFromImage(
        image, 1.0/255.0, cv::Size(640, 640),
        cv::Scalar(0, 0, 0), true, false);

    // Run inference
    net.setInput(blob);
    cv::Mat output = net.forward();

    std::cout << "Output shape: " << output.size << "\n";
    return 0;
}

Cross-Platform Considerations

OpenCV behaves differently across platforms. Handle these variations in your CMakeLists.txt:

# Cross-platform OpenCV project
cmake_minimum_required(VERSION 3.20)
project(CrossPlatformVision LANGUAGES CXX)

# Platform-specific OpenCV hints
if(WIN32)
    # Windows: OpenCV from pre-built binaries
    set(OpenCV_DIR "C:/opencv/build" CACHE PATH "OpenCV build directory")
elseif(APPLE)
    # macOS: OpenCV from Homebrew
    list(APPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/opencv")
endif()
# Linux: system package or /usr/local (no hints needed)

find_package(OpenCV 4.5 REQUIRED COMPONENTS core imgproc highgui)

add_executable(app main.cpp)
target_link_libraries(app PRIVATE ${OpenCV_LIBS})

# Platform-specific video backend selection
if(WIN32)
    target_compile_definitions(app PRIVATE CV_BACKEND_MSMF)
elseif(APPLE)
    target_compile_definitions(app PRIVATE CV_BACKEND_AVFOUNDATION)
else()
    target_compile_definitions(app PRIVATE CV_BACKEND_V4L2)
endif()
Pitfall — OpenCV Version Mismatch: Linking your application against a different OpenCV version than what was used at compile time causes subtle crashes. Always verify ${OpenCV_VERSION} matches your development environment, especially in CI pipelines that may have a different system OpenCV installed.
Best Practices Summary:
  • Use BUILD_LIST to limit modules when building from source
  • Prefer imported targets (opencv_core) over ${OpenCV_LIBS} variable
  • Set OpenCV_DIR to the directory containing OpenCVConfig.cmake
  • Use CUDA modules for batch processing — overhead makes single-image GPU slower
  • Pin the OpenCV version in find_package() for reproducible builds
  • Build contrib from source when you need specialized modules