Cv2.Canny: примеры (PYTHON)

Функция cv2.Canny для обнаружения границ в обработке изображений
Раздел: OpenCV, Обработка изображений
cv2.Canny(image: ndarray, threshold1: float, threshold2: float): ndarray

Описание функции cv2.Canny

Функция cv2.Canny() из библиотеки OpenCV предназначена для обнаружения границ на изображениях с помощью алгоритма Кэнни. Этот метод включает несколько этапов: применение фильтра Гаусса для уменьшения шума, вычисление градиентов интенсивности, подавление немаксимумов и гистерезисную пороговую фильтрацию.

Аргументы функции:

  • image (uint8): входное одноканальное или трёхканальное изображение в оттенках серого. При трёх каналах они автоматически конвертируются.
  • threshold1 (double): нижнее значение порога для гистерезиса.
  • threshold2 (double): верхнее значение порога для гистерезиса.
  • edges (OutputArray): необязательный выходной параметр для карты границ (обычно не используется явно).
  • apertureSize (int): размер оператора Собеля для вычисления градиентов (по умолчанию 3, допустимые значения 3, 5, 7).
  • L2gradient (bool): флаг вычисления нормы градиента. Если False - используется L1-норма (|dI/dx|+|dI/dy|), если True - более точная L2-норма (sqrt((dI/dx)^2+(dI/dy)^2)).

Возвращаемое значение:

Функция возвращает одноканальное изображение (матрицу) того же размера, что и входное, где ненулевые пиксели соответствуют обнаруженным границам.

Короткие примеры использования

Пример 1: Базовое использование

import cv2
import numpy as np

img = cv2.imread('image.jpg', 0)
edges = cv2.Canny(img, 100, 200)
cv2.imshow('Edges', edges)
cv2.waitKey(0)
Результат: отображается окно с чёрно-белым изображением, где белые линии соответствуют границам.

Пример 2: С изменением размера апертуры

edges = cv2.Canny(img, 50, 150, apertureSize=5)
Границы вычисляются с использованием оператора Собеля 5×5, что может выявить более плавные переходы.

Пример 3: С использованием L2-градиента

edges = cv2.Canny(img, 80, 160, L2gradient=True)
Границы определяются с более точным вычислением величины градиента, что обычно даёт меньше шума.

Похожие функции в Python

cv2.Sobel(): вычисляет производные изображения по x и/или y. Позволяет получить градиенты, но без последующей пороговой обработки по алгоритму Кэнни. Используется, когда нужны исходные градиенты.

cv2.Laplacian(): вычисляет лапласиан изображения. Обнаруживает границы как области быстрого изменения второй производной. Чувствителен к шуму.

cv2.Scharr(): вариант оператора Собеля с повышенной точностью. Применяется для более точного вычисления градиентов при небольшом размере ядра.

skimage.filters.sobel() из библиотеки scikit-image: аналог Собеля с дополнительными возможностями интеграции в конвейеры обработки изображений.

Альтернативы в других языках

JavaScript (OpenCV.js):

let src = cv.imread('canvasInput');
let dst = new cv.Mat();
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);
cv.Canny(gray, dst, 50, 100);
cv.imshow('canvasOutput', dst);

Java (OpenCV):

Mat src = Imgcodecs.imread("image.jpg", Imgcodecs.IMREAD_GRAYSCALE);
Mat edges = new Mat();
Imgproc.Canny(src, edges, 100, 200);

C# (Emgu CV):

using (Mat src = new Mat("image.jpg", ImreadModes.Grayscale))
using (Mat edges = new Mat())
{
    CvInvoke.Canny(src, edges, 100, 200);
}

Golang (GoCV):

src := gocv.IMRead("image.jpg", gocv.IMReadGrayScale)
edges := gocv.NewMat()
gocv.Canny(src, &edges, 100, 200)

Основное отличие от Python-версии - синтаксис вызова и управление памятью, но параметры и логика работы идентичны.

Типичные ошибки

1. Неправильный тип изображения

img = cv2.imread('image.jpg')  # 3 канала BGR
edges = cv2.Canny(img, 100, 200)  # Работает, но лучше конвертировать явно
Функция сработает, но производительность может снизиться из-за внутренней конвертации.

2. Пороги в неправильном порядке

edges = cv2.Canny(img, 200, 100)  # threshold1 > threshold2
Функция переставляет пороги местами, но логика обнаружения границ может нарушиться.

3. Слишком низкие пороги для зашумленного изображения

edges = cv2.Canny(noisy_img, 10, 30)
Результат содержит много шумовых границ, изображение выглядит «замусоренным».

Изменения в последних версиях

В OpenCV 4.x значительных изменений в работе cv2.Canny() не произошло. Основные улучшения касались внутренней оптимизации и поддержки новых типов данных. В версии 4.5.1 была улучшена обработка изображений с плавающей точкой. Важно отметить, что в новых версиях рекомендуется использовать cv2.Canny() вместо устаревшего C-интерфейса.

Расширенные примеры

Пример 1: Адаптивные пороги на основе статистики изображения

Пример python
import cv2
import numpy as np

img = cv2.imread('image.jpg', 0)
median = np.median(img)
lower = int(max(0, 0.7 * median))
upper = int(min(255, 1.3 * median))
edges = cv2.Canny(img, lower, upper)
Пороги автоматически подстраиваются под статистику изображения.

Пример 2: Последовательное применение с разными параметрами

Пример python
edges1 = cv2.Canny(img, 50, 100)
edges2 = cv2.Canny(img, 100, 150)
combined = cv2.bitwise_or(edges1, edges2)
Объединение результатов с разными порогами позволяет захватить границы разной контрастности.

Пример 3: Обработка видео в реальном времени

Пример python
cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150)
    cv2.imshow('Live Edges', edges)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
Вывод границ с веб-камеры в реальном времени.

Пример 4: Использование с бинарной маской

Пример python
mask = np.zeros(img.shape, dtype=np.uint8)
# ... заполнение маски ...
masked_edges = cv2.bitwise_and(edges, edges, mask=mask)
Обнаружение границ только в определённой области изображения.

питон cv2.Canny function comments

En
Cv2.Canny Edge detection