Canny图像边缘检测
程序员文章站
2024-01-28 11:30:04
...
- C++ API说明
void cv::Canny (
InputArray image, (输入图像:8-bit)
OutputArray edges, (输出边缘图像:单通道,8-bit,size与输入图像一致)
double threshold1, (阈值1)第一个滞后性阈值【低阈值】。值越大,找到的边缘越少
double threshold2, (阈值2)第二个滞后性阈值【高阈值】。
int apertureSize=3, (Sober算子大小)
bool L2gradient=false (是否采用更精确的方式计算图像梯度)
)
void cv::Canny (
InputArray dx, (输入图像在x方向的导数:16-bit(CV_16SC1或CV_16SC3))
InputArray dy, (输入图像在y方向的导数:16-bit(CV_16SC1或CV_16SC3))
OutputArray edges, (输出边缘图像:单通道,8-bit,size与输入图像一致)
double threshold1, (阈值1)第一个滞后性阈值【低阈值】。值越大,找到的边缘越少
double threshold2, (阈值2)第二个滞后性阈值【高阈值】。
bool L2gradient=false (是否采用更精确的方式计算图像梯度)
)
Parameters
image 8-bit input image.
edges output edge map; single channels 8-bit image, which has the same size as image .
threshold1 first threshold for the hysteresis procedure.
threshold2 second threshold for the hysteresis procedure.
apertureSize aperture size for the Sobel operator.
L2gradient a flag, indicating whether a more accurate L2 norm =(dI/dx)2+(dI/dy)2−−
−−−−−−−−
−−−−−−√ should be used to calculate the image gradient magnitude ( L2gradient=true ),
or whether the default L1 norm =|dI/dx|+|dI/dy| is enough ( L2gradient=false ).
1 # xgrad = cv.Sobel(gray, cv.CV_16SC1, 1, 0) #x方向梯度
2 # ygrad = cv.Sobel(gray, cv.CV_16SC1, 0, 1) #y方向梯度
3 # edge_output = cv.Canny(xgrad, ygrad, 50, 150)
4 edge_output = cv.Canny(gray, 50, 150)
注:其中第4行代码可以用1、2、3行代码代替!两种方法效果一样。
原理
JohnCanny于1986年提出Canny算子,是一个多级边缘检测算法。它与Marr(LoG)边缘检测方法类似,也属于是先平滑后求导数的方法。被很多人认为是边缘检测的最优算法, 最优边缘检测的评价标准主要有三个:
- 低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。
- 高定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。
- 最小响应: 图像中的边缘只能标识一次。
步骤
它是一个多阶段的算法,即由多个步骤构成。
1.图像降噪
消除噪声。 使用高斯平滑滤波器卷积降噪。 下面是一个 的高斯内核:
2.计算图像梯度
计算梯度幅值和方向。计算图像梯度可以得到图像的边缘,因为边缘也是灰度变化明显,梯度灰度变化也明显。这一步可以检测到可能的边缘。由于灰度变化大的地方可能是边缘,也可能不是边缘,但这一步将所有可能是边缘的地方集合。 此处使用Sobel滤波器:
a.运用一对卷积阵列 (分别作用于 和 方向):
在上面的三个模板中,Gx为水平x方向的模板,Gy为 垂直y方向的模板,K为领域标记矩阵。
b.使用下列公式计算梯度幅值和方向:
梯度方向近似得到四个可能角度一般是 0, 45, 90, 135。
3.非极大值抑制
非极大值 抑制。 这一步排除非边缘像素, 仅仅保留了一些细线条(候选边缘)。灰度变化的地方通常比较集中,将局部范围内梯度方向上灰度变化最大的保留下来,其它的不保留,这样处理可以剔除掉很多不是边缘的点。将宽边缘(多个像素)变成一个单(单像素)边缘。即“宽边缘”变成“单边缘”。
4.双阈值筛选或者滞后阈值
最后一步,通过非极大值抑制后,仍然有很多的可能边缘点,进一步的设置一个双阈值,即低阈值(low)、高阈值(high)。
- 某一像素的灰度值超过high 阈值, 该像素被保留为边缘像素。
- 某一像素的灰度值小于low 阈值, 该像素被排除。
- 如果某一像素的灰度值在两个阈值之间,该像素仅仅在连接到一个高于high阈值的像素时被保留。
Canny 推荐的 高:低 阈值比在 2:1 到3:1之间。
最后看代码效果:
#include "opencv.hpp"
using namespace cv;
void main()
{
Mat src = imread("2019_04_13.jpg", IMREAD_COLOR);
Mat gray;
cvtColor(src , gray, CV_BGR2GRAY);
Mat canny;
Canny(gray, canny, 60, 180);
}
参考: