OpenCV для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

OpenCV для C++: полное руководство с примерами

1. Что это и зачем нужна

OpenCV (Open Source Computer Vision Library) — это мощная библиотека с открытым исходным кодом, предназначенная для решения задач компьютерного зрения и обработки изображений. Написанная на C++ с поддержкой Python, Java и других языков, она предоставляет более 2500 оптимизированных алгоритмов для анализа, фильтрации, трансформации и распознавания визуальной информации. OpenCV активно используется в робототехнике, системах видеонаблюдения, медицинской визуализации, дополненной реальности и автономных транспортных средствах.

Зачем она нужна? В современном мире огромные объёмы данных поступают в виде изображений и видео. Ручная обработка такого потока невозможна. OpenCV позволяет автоматизировать такие задачи, как обнаружение лиц, отслеживание объектов, калибровка камер, построение карт глубины, сегментация изображений и даже обучение нейросетей для распознавания образов. Библиотека предоставляет готовые высокопроизводительные инструменты, избавляя разработчика от необходимости реализовывать сложные математические алгоритмы с нуля.

Для C++ OpenCV является де-факто стандартом индустрии. Благодаря прямой работе с памятью и низкоуровневым доступом к пикселям, C++ версия обеспечивает максимальную скорость выполнения, что критично для real-time приложений (например, обработка видео с камеры в 60 FPS). Библиотека активно развивается сообществом и корпорациями (Intel, Willow Garage, Itseez), а её модульная архитектура позволяет подключать только нужные компоненты, экономя ресурсы.

2. Установка

Установка OpenCV для C++ требует компиляции исходного кода или использования пакетного менеджера. Ниже приведены основные способы.

2.1. Установка через vcpkg (рекомендуется для Windows)

# Установите vcpkg, если ещё не установлен
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat

# Установите OpenCV с поддержкой дополнительных модулей (contrib)
.\vcpkg install opencv4[contrib,nonfree]:x64-windows

# Интеграция с Visual Studio
.\vcpkg integrate install

2.2. Установка через apt (Linux / Ubuntu / Debian)

sudo apt update
sudo apt install libopencv-dev

2.3. Установка через brew (macOS)

brew install opencv

2.4. Сборка из исходников (максимальная гибкость)

git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
cd opencv
mkdir build && cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE \
      -D CMAKE_INSTALL_PREFIX=/usr/local \
      -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
      -D WITH_TBB=ON \
      -D WITH_V4L=ON \
      -D WITH_OPENGL=ON ..
make -j$(nproc)
sudo make install

После установки не забудьте указать пути к заголовочным файлам и библиотекам в вашей IDE (например, Visual Studio, CLion, CMake). Пример для CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(MyOpenCVProject)
find_package(OpenCV REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main ${OpenCV_LIBS})

3. Быстрый старт — минимальный рабочий пример

Следующий код загружает изображение, преобразует его в оттенки серого и сохраняет результат. Это классический "Hello, World!" для компьютерного зрения.

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // Загружаем цветное изображение
    cv::Mat image = cv::imread("input.jpg");
    if (image.empty()) {
        std::cerr << "Ошибка: не удалось загрузить изображение!" << std::endl;
        return -1;
    }

    // Преобразуем в оттенки серого
    cv::Mat gray;
    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

    // Сохраняем результат
    cv::imwrite("output_gray.jpg", gray);

    // Показываем изображения в окнах
    cv::imshow("Original", image);
    cv::imshow("Gray", gray);
    cv::waitKey(0); // Ожидание нажатия клавиши

    return 0;
}

Компиляция: g++ -std=c++17 main.cpp -o main `pkg-config --cflags --libs opencv4`

4. Основные методы/функции/классы

Рассмотрим ключевые компоненты OpenCV, которые используются в 90% проектов.

4.1. cv::Mat — основной класс для работы с изображениями

Сигнатура: class cv::Mat (конструкторы, операторы присваивания, методы доступа)

Что делает: Представляет n-мерный массив, используемый для хранения изображений (пикселей), матриц преобразований, гистограмм и т.д. Поддерживает автоматическое управление памятью через подсчёт ссылок.

// Создание пустой матрицы
cv::Mat emptyMat;

// Создание матрицы 300x300, 3 канала (RGB), заполненной синим цветом
cv::Mat blueImage(300, 300, CV_8UC3, cv::Scalar(255, 0, 0));

// Доступ к пикселю (строка 100, столбец 50)
cv::Vec3b pixel = blueImage.at<cv::Vec3b>(100, 50);
std::cout << "B: " << (int)pixel[0] << " G: " << (int)pixel[1] << " R: " << (int)pixel[2] << std::endl;

// Клонирование (глубокое копирование)
cv::Mat clone = blueImage.clone();

// Создание региона интереса (ROI)
cv::Rect roi(50, 50, 100, 100);
cv::Mat subImage = blueImage(roi);

4.2. cv::imread — загрузка изображения

Сигнатура: cv::Mat cv::imread(const String& filename, int flags = IMREAD_COLOR)

Что делает: Читает изображение из файла. Флаги позволяют загрузить его в цвете (IMREAD_COLOR), в оттенках серого (IMREAD_GRAYSCALE) или без изменений (IMREAD_UNCHANGED).

cv::Mat colorImg = cv::imread("photo.jpg", cv::IMREAD_COLOR);
cv::Mat grayImg = cv::imread("photo.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat unchangedImg = cv::imread("photo.png", cv::IMREAD_UNCHANGED); // сохраняет альфа-канал

if (colorImg.empty()) {
    std::cerr << "Файл не найден!" << std::endl;
}

4.3. cv::cvtColor — преобразование цветовых пространств

Сигнатура: void cv::cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0)

Что делает: Конвертирует изображение из одного цветового пространства в другое (BGR ↔ Gray, BGR ↔ HSV, BGR ↔ Lab и т.д.).

cv::Mat hsv;
cv::cvtColor(colorImg, hsv, cv::COLOR_BGR2HSV);

// Извлечение отдельных каналов HSV
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
// channels[0] - H (оттенок), channels[1] - S (насыщенность), channels[2] - V (значение)

4.4. cv::GaussianBlur — размытие по Гауссу

Сигнатура: void cv::GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT)

Что делает: Применяет фильтр Гаусса для сглаживания изображения. Эффективно удаляет высокочастотный шум (гауссов шум). Размер ядра (ksize) должен быть нечётным.

cv::Mat blurred;
cv::GaussianBlur(colorImg, blurred, cv::Size(5, 5), 1.5);

// Быстрое размытие для больших изображений (Box Filter)
cv::Mat fastBlur;
cv::blur(colorImg, fastBlur, cv::Size(5, 5));

4.5. cv::Canny — детектор границ Кэнни

Сигнатура: void cv::Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false)

Что делает: Один из самых популярных алгоритмов выделения границ. Использует два порога: нижний (threshold1) для слабых границ и верхний (threshold2) для сильных. Рекомендуемое соотношение 1:2 или 1:3.

cv::Mat edges;
cv::Canny(grayImg, edges, 50, 150);

// Отображение результата
cv::imshow("Edges", edges);

4.6. cv::findContours — поиск контуров

Сигнатура: void cv::findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point())

Что делает: Находит контуры (границы) объектов на бинарном изображении. Параметр mode определяет тип извлечения (RETR_EXTERNAL — только внешние, RETR_TREE — полная иерархия). method задаёт аппроксимацию контура (CHAIN_APPROX_SIMPLE сжимает горизонтальные/вертикальные линии).

std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(edges, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

// Рисуем все контуры на копии исходного изображения
cv::Mat drawing = colorImg.clone();
for (size_t i = 0; i < contours.size(); i++) {
    cv::drawContours(drawing, contours, (int)i, cv::Scalar(0, 255, 0), 2);
}

// Выводим количество найденных контуров
std::cout << "Найдено контуров: " << contours.size() << std::endl;

4.7. cv::HoughCircles — поиск окружностей

Сигнатура: void cv::HoughCircles(InputArray image, OutputArray circles, int method, double dp, double minDist, double param1 = 100, double param2 = 100, int minRadius = 0, int maxRadius = 0)

Что делает: Обнаруживает окружности на изображении с помощью преобразования Хафа. Рекомендуется предварительно применить размытие и детектор границ. Параметр dp — обратное отношение разрешения аккумулятора к разрешению изображения.

cv::Mat grayBlurred;
cv::GaussianBlur(grayImg, grayBlurred, cv::Size(9, 9), 2);

std::vector<cv::Vec3f> circles;
cv::HoughCircles(grayBlurred, circles, cv::HOUGH_GRADIENT, 1, 20, 100, 30, 10, 50);

for (size_t i = 0; i < circles.size(); i++) {
    cv::Vec3f c = circles[i];
    cv::circle(colorImg, cv::Point(c[0], c[1]), (int)c[2], cv::Scalar(0, 0, 255), 3);
    cv::circle(colorImg, cv::Point(c[0], c[1]), 2, cv::Scalar(0, 255, 0), 3);
}

4.8. cv::VideoCapture — захват видео

Сигнатура: class cv::VideoCapture (конструкторы: VideoCapture(const String& filename), VideoCapture(int index))

Что делает: Позволяет захватывать видео из файла или с камеры (по индексу устройства). Предоставляет методы read() или оператор >> для получения кадров.

cv::VideoCapture cap(0); // 0 — первая веб-камера
if (!cap.isOpened()) {
    std::cerr << "Не удалось открыть камеру!" << std::endl;
    return -1;
}

cv::Mat frame;
while (cap.read(frame)) {
    cv::imshow("Webcam", frame);
    if (cv::waitKey(30) == 27) break; // ESC для выхода
}
cap.release();

4.9. cv::warpAffine — аффинные преобразования

Сигнатура: void cv::warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar& borderValue = Scalar

Рекомендаций