Как обнаружить контуры на изображении?

Обнаружение контуров на изображении — это важная задача в компьютерном зрении, направленная на выделение замкнутых границ объектов. Контур представляет собой последовательность точек, соединённых таким образом, чтобы образовывать границу между разными областями изображения. В OpenCV для этого используется функция cv2.findContours() в сочетании с другими методами предварительной обработки.

Общий процесс обнаружения контуров

Чтобы корректно найти контуры, изображение должно быть подготовлено:

  1. Преобразование в оттенки серого (grayscale).

  2. Фильтрация шума (например, с помощью гауссового размытия).

  3. Бинаризация (пороговое преобразование) или детекция границ (например, cv2.Canny()).

  4. Вызов cv2.findContours() на обработанном изображении.

Пример пошагово

import cv2
\# Загрузка изображения
image = cv2.imread('example.jpg')
\# Преобразование в градации серого
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
\# Размытие (для удаления шума)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
\# Детектор границ (или можно использовать threshold)
edges = cv2.Canny(blurred, 50, 150)
\# Поиск контуров
contours, hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
\# Отрисовка контуров
contoured_image = image.copy()
cv2.drawContours(contoured_image, contours, -1, (0, 255, 0), 2)
cv2.imshow('Contours', contoured_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Аргументы функции cv2.findContours()

contours, hierarchy = cv2.findContours(image, mode, method)
  • image — бинарное изображение (только 0 и 255). Контуры ищутся по белым пикселям.

  • mode — способ поиска контуров:

    • cv2.RETR_EXTERNAL — только внешние контуры.

    • cv2.RETR_LIST — все контуры без иерархии.

    • cv2.RETR_TREE — все контуры с полной иерархией вложенности.

    • cv2.RETR_CCOMP — внешние и внутренние уровни отдельно.

  • method — способ аппроксимации контуров:

    • cv2.CHAIN_APPROX_NONE — сохраняются все точки.

    • cv2.CHAIN_APPROX_SIMPLE — удаляются избыточные точки на прямых.

Результат cv2.findContours()

  • contours — список массивов NumPy, каждый из которых содержит координаты точек одного контура.

  • hierarchy — массив, описывающий иерархические отношения между контурами (родитель, потомок и т.д.).

Бинаризация как альтернатива Canny

Если изображение хорошо контрастное, можно применить простое пороговое преобразование:

ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

Или адаптивное пороговое преобразование:

adaptive = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2
)
contours, _ = cv2.findContours(adaptive, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

Как анализировать контуры

После нахождения контуров можно извлекать полезные характеристики:

  1. **Площадь
    **
area = cv2.contourArea(cnt)
  1. **Периметр
    **
perimeter = cv2.arcLength(cnt, True)
  1. **Аппроксимация
    **
approx = cv2.approxPolyDP(cnt, 0.02 \* perimeter, True)
  1. **Ограничивающий прямоугольник
    **
x, y, w, h = cv2.boundingRect(cnt)
  1. **Минимальный охватывающий круг
    **
(x, y), radius = cv2.minEnclosingCircle(cnt)
  1. **Моменты контура (для определения центра масс)
    **
M = cv2.moments(cnt)
cx = int(M\["m10"\] / M\["m00"\])
cy = int(M\["m01"\] / M\["m00"\])

Удаление мелких шумов

Иногда cv2.findContours() возвращает много маленьких "мусорных" контуров. Их можно отфильтровать по площади:

filtered = \[cnt for cnt in contours if cv2.contourArea(cnt) > 100\]

Иерархия контуров

Если используется cv2.RETR_TREE или cv2.RETR_CCOMP, hierarchy покажет вложенность:

\[Next, Previous, First_Child, Parent\]

Например, это важно для распознавания фигур с отверстиями (например, буквы O, A, P).

Применения в задачах компьютерного зрения

  • Распознавание символов — предварительное выделение областей.

  • Подсчёт объектов — по количеству контуров.

  • Анализ формы объектов — извлечение геометрических признаков.

  • Выделение ROI (областей интереса).

  • Отслеживание движения — если применять к последовательности кадров.

  • Контурная сегментация — в медицинских изображениях, спутниковых снимках.

Возможные проблемы

  • cv2.findContours() работает только с чёрно-белыми изображениями (0 и 255), иначе результат будет непредсказуем.

  • Очень шумные или плохо освещённые изображения могут привести к множеству ложных контуров.

  • Для сложных объектов необходимо комбинировать Canny, размытие, морфологические операции (cv2.dilate, cv2.erode) для улучшения результата.

Обнаружение контуров является ключевым этапом во многих алгоритмах обработки изображений и машинного зрения. В сочетании с предобработкой и анализом формы контуры позволяют эффективно находить и анализировать объекты на изображениях.