Cv2.Canny: примеры (PYTHON)
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: Адаптивные пороги на основе статистики изображения
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: Последовательное применение с разными параметрами
edges1 = cv2.Canny(img, 50, 100)
edges2 = cv2.Canny(img, 100, 150)
combined = cv2.bitwise_or(edges1, edges2)Объединение результатов с разными порогами позволяет захватить границы разной контрастности.
Пример 3: Обработка видео в реальном времени
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: Использование с бинарной маской
mask = np.zeros(img.shape, dtype=np.uint8)
# ... заполнение маски ...
masked_edges = cv2.bitwise_and(edges, edges, mask=mask)Обнаружение границ только в определённой области изображения.