Различные статьи по Qt и c++

Базовые операции обработки изображений: фильтры, размытие, морфология

Введение

После основ работы с Mat и загрузки/сохранения изображений переходим к реальной обработке — в этой статье разберём базовые операции из модуля imgproc: фильтрацию (размытие, повышение резкости) и морфологические операции (эрозия, дилатация), часто используемые как предварительная обработка перед более сложным анализом изображения.

Концепция

Размытие (cv::GaussianBlur, cv::medianBlur) сглаживает изображение, усредняя значения соседних пикселей согласно определённому «ядру» (kernel) — это часто используется для подавления шума перед последующей обработкой (детекция контуров статьи 566, детекция признаков статьи 567), поскольку шум на изображении может создавать ложные, нежелательные срабатывания этих более сложных алгоритмов. Морфологические операции (эрозия, дилатация, и их комбинации — открытие и закрытие) работают преимущественно с бинарными (чёрно-белыми) изображениями, изменяя форму объектов на изображении — эрозия «сжимает» светлые области (удаляя тонкие выступы и мелкий шум), дилатация «расширяет» их (заполняя небольшие пробелы), и эти операции часто используются после пороговой обработки (статья 565) для очистки результата от мелких артефактов.

Пример кода: Базовые операции обработки изображений

#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat image = cv::imread("photo.jpg");
    if (image.empty()) return 1;

    cv::Mat blurred;
    cv::GaussianBlur(image, blurred, cv::Size(15, 15), 0); // размер ядра 15x15 — больше = сильнее размытие
    cv::imwrite("blurred.png", blurred);

    cv::Mat medianBlurred;
    cv::medianBlur(image, medianBlurred, 9); // медианное размытие — особенно эффективно против "соль-перец" шума
    cv::imwrite("median_blurred.png", medianBlurred);

    return 0;
}
// Морфологические операции — эрозия и дилатация на бинарном изображении
#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat binary = cv::imread("binary_mask.png", cv::IMREAD_GRAYSCALE); // загрузка в оттенках серого

    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5)); // форма "структурного элемента"

    cv::Mat eroded;
    cv::erode(binary, eroded, kernel); // СЖИМАЕТ светлые области — удаляет мелкий шум

    cv::Mat dilated;
    cv::dilate(binary, dilated, kernel); // РАСШИРЯЕТ светлые области — заполняет небольшие пробелы

    // "Открытие" — эрозия, затем дилатация — удаляет мелкий шум, СОХРАНЯЯ общий размер объектов
    cv::Mat opened;
    cv::morphologyEx(binary, opened, cv::MORPH_OPEN, kernel);

    cv::imwrite("opened.png", opened);
    return 0;
}

Пояснения к коду

cv::GaussianBlur(image, blurred, cv::Size(15, 15), 0) показывает типичный вызов размытия — размер ядра (15, 15) определяет, насколько широкая окрестность каждого пикселя учитывается при усреднении (большее ядро даёт более сильное, заметное размытие), а последний параметр (0) указывает на автоматический расчёт стандартного отклонения распределения Гаусса на основе размера ядра. cv::medianBlur показывает альтернативный тип размытия, особенно эффективный против специфичного типа шума «соль и перец» (отдельные, случайно разбросанные полностью чёрные или белые пиксели) — медианная фильтрация заменяет каждый пиксель медианным (а не средним) значением окрестности, что лучше устраняет резкие, выделяющиеся отдельные точки шума по сравнению с обычным усреднением, которое лишь «размазывает» такой шум, не устраняя его полностью. Пример с erode/dilate/morphologyEx(MORPH_OPEN) показывает прогрессию от базовых морфологических операций к их комбинации — «открытие» (эрозия с последующей дилатацией тем же структурным элементом) удаляет мелкие, шумовые объекты, при этом восстанавливая исходный размер оставшихся, более крупных объектов (которые были временно уменьшены эрозией, а затем восстановлены последующей дилатацией), что даёт более качественную очистку шума по сравнению с применением только эрозии в одиночку.

Подводные камни

  • Использование избыточно большого размера ядра размытия, теряющего важные детали изображения вместе с подавляемым шумом — слишком сильное размытие может уничтожить полезную, нужную для последующей обработки информацию (например, контуры объектов, статья 566, становятся менее чёткими при избыточном размытии), и размер ядра должен быть подобран с учётом баланса между реальным подавлением шума и сохранением значимых деталей изображения, необходимых для конкретной дальнейшей задачи.
  • Применение операций, ожидающих бинарное (чёрно-белое) изображение, к цветному или просто не предварительно обработанному пороговой обработкой изображению — морфологические операции концептуально предназначены преимущественно для бинарных масок (результата пороговой обработки, статья 565, или сегментации), и применение их непосредственно к необработанному цветному фотографическому изображению (хотя технически возможно для каждого канала по отдельности) обычно не даёт содержательного, полезного результата без предварительного приведения изображения к подходящему, бинарному виду.
  • Несогласованный выбор формы и размера структурного элемента (kernel) для морфологических операций без учёта реальной формы и размера объектов на конкретном изображении — cv::MORPH_RECT (прямоугольная форма) не всегда оптимальна для всех случаев, и OpenCV предоставляет альтернативы (MORPH_ELLIPSE, MORPH_CROSS), более подходящие для определённых форм объектов, и выбор как формы, так и размера структурного элемента должен соответствовать реальным характеристикам обрабатываемых объектов на конкретном изображении.
  • Применение последовательности фильтров без понимания их совокупного эффекта и вычислительной стоимости для приложений, обрабатывающих видео в реальном времени (статья 568) — каждая операция фильтрации/морфологии имеет свою вычислительную стоимость, и для конвейера обработки, должного выполняться в реальном времени (например, 30 кадров в секунду), совокупная стоимость последовательно применённых операций должна быть явно измерена и учтена, чтобы не превысить доступный бюджет времени на обработку каждого отдельного кадра видеопотока.