【OpenCV-Python】教程:3-7 Canny边缘检测

OpenCV Python Canny 边缘检测

【目标】

  • Canny 边缘检测的概念
  • cv2.Canny

【原理】

1. 去噪

由于边缘检测非常容易收到图像的噪声影响,第一步使用 5x5 高斯滤波去除图像中的噪声。

2. 寻找图像的亮度梯度

在平滑后(去噪后)的图像利用 Sobel 算子计算图像的 X-, Y- 的一阶导数 G ( x ) G(x) G(x) G ( y ) G(y) G(y),从这两幅图像中我们可以获得边缘的梯度值和方向。

E d g e   G r a d i e n t ( G ) = G x 2 + G y 2 Edge \space Gradient(G) = \sqrt{G_x^2+ G_y^2} Edge Gradient(G)=Gx2+Gy2

A n g l e ( θ ) = t a n − 1 ( G x G y ) Angle(\theta) = tan^{-1}\left( \frac{G_x}{G_y} \right) Angle(θ)=tan1(GyGx)

渐变方向始终垂直于边,被四舍五入到垂直、水平和两个对角四个角度里。

3. 非最大值抑制

获得梯度大小和方向后,对图像进行全扫描,去除可能不构成边缘的任何不需要的像素。在每个像素处,检查像素在梯度方向是否是其领域中的局部最大值。

【OpenCV-Python】教程:3-7 Canny边缘检测_第1张图片

点A位于垂直边缘上,梯度方向为 A->B, B 和 C 都是梯度方向上的点,如果 A 是邻域内最大的,则保留,否则设置为0。简而言之,会得到一个细的边缘。

4. 滞后阈值

这个阶段决定哪些是真正的边缘,哪些不是。为此,我们需要两个阈值,minVal和maxVal,梯度强度大于maxVal确定是边缘,低于minVal值的边缘点被抛弃,位于这两个值中间的值,根据其邻域点的属性来决定,如果连接到强边缘,则被判定为强边缘,否则丢弃。

【OpenCV-Python】教程:3-7 Canny边缘检测_第2张图片

上图中,可以看出,尽管C点在maxVal以下,但是与A连接,则C和A都是强边缘点。而B没有强边缘连接,则被丢弃。

【代码】

【OpenCV-Python】教程:3-7 Canny边缘检测_第3张图片

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg',0)
edges = cv2.Canny(img,100,200)

cv2.imshow("src", img)
cv2.imshow("edge", edges)

cv2.waitKey(0)
cv2.destroyAllWindows()

【OpenCV-Python】教程:3-7 Canny边缘检测_第4张图片

  • trackerbar 控制 Canny 边缘检测阈值
import numpy as np
import cv2

# 空函数
def nothing(x):
    pass

img = cv2.imread('messi5.jpg', 0)
cv2.namedWindow('image')

cv2.createTrackbar('min', 'image', 10, 200, nothing)
cv2.createTrackbar('max', 'image', 0, 255, nothing)

cv2.setTrackbarPos('min', 'image', 50)
cv2.setTrackbarPos('max', 'image', 150)


while(1):
    cv2.imshow('image', img)
    if cv2.waitKey(2) & 0xFF == 27:
        break
    
    minVal = cv2.getTrackbarPos('min', 'image')
    maxVal = cv2.getTrackbarPos('max', 'image')
    
    if maxVal < minVal:
        maxVal = minVal + 10
        cv2.setTrackbarPos('max', 'image', maxVal)

    edges = cv2.Canny(img, minVal, maxVal)
    cv2.imshow('canny', edges)

cv2.destroyAllWindows()

【接口】

void cv::Canny	(	InputArray 	image,
OutputArray 	edges,
double 	threshold1,
double 	threshold2,
int 	apertureSize = 3,
bool 	L2gradient = false 
);


void cv::Canny	(	InputArray 	dx,
InputArray 	dy,
OutputArray 	edges,
double 	threshold1,
double 	threshold2,
bool 	L2gradient = false 
);
cv.Canny(	image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]	) ->	edges
cv.Canny(	dx, dy, threshold1, threshold2[, edges[, L2gradient]]	) ->	edges

用Canny方法计算图像的边缘

  • image: 8位输入图像
  • edges: 输出的边缘图像, 单通道8位图像,尺寸与原图一致
  • threshold1: 滞后过程的第一阈值
  • threshold2: 滞后过程的第二阈值
  • L2gradient: 一个决定是否需要更好精度的标志,L2gradient=true
  • dx: 输入图像的16位x导数
  • dy: 输入图像的16位y导数

【参考】

  1. John Canny. A computational approach to edge detection. Pattern Analysis and Machine Intelligence, IEEE Transactions on, (6):679–698, 1986.
  2. OpenCV官网文档

你可能感兴趣的:(#,OpenCV,#,Python,opencv,python)