void Canny( InputArray _src, OutputArray _dst,
double low_thresh, double high_thresh,
int aperture_size, bool L2gradient )
相信很多同学在使用Canny函数的时候只知道高阈值和低阈值调高或者调低有什么用,就像下面的总结一样:
- 低于阈值1的像素点会被认为不是边缘;
- 高于阈值2的像素点会被认为是边缘;
- 在阈值1和阈值2之间的像素点,若与第2步得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘。
但其实 并没有真正理解高低阈值是怎样来的,并且不知道怎么调整参数来改变Canny的效果,只能一个一个值的试。那下面我就会带着大家从Canny源码一步一步解析,并且教大家怎么使用高低阈值。
Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0, cv::BORDER_REPLICATE);
Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, cv::BORDER_REPLICATE);
源码中有这两段代码,通过sobel算子计算当前点的水平和垂直方向的梯度值,并存放在dx和dy中
文章来源地址https://www.toymoban.com/news/detail-737231.html
for (int i = 0; i <= src.rows; i++) // i 表示第i行
{
// i == 0 时,_norm 指向 mag_buf[1]
// i > 0 时, _norm 指向 mag_buf[2]
// +1 表示跳过每行的第一个元素,因为是后扩展的边,不可能是边缘
int* _norm = mag_buf[(i > 0) + 1] + 1;
short* _dx = dx.ptr<short>(i); // _dx指向dx矩阵的第i行
short* _dy = dy.ptr<short>(i); // _dy指向dy矩阵的第i行
if (!L2gradient) // 如果 L2gradient为false
{
for (int j = 0; j < src.cols*cn; j++) // 对第i行里的每一个值都进行计算
_norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j]));
// 用||+||计算
}
else
{
for (int j = 0; j < src.cols*cn; j++)
//用平方计算,当 L2gradient为 true时高低阈值都被平方了,所以此处_norm[j]无需开平方
_norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j]; //
}
_norm[-1] = _norm[src.cols] = 0; // 最后一列和第一列的梯度幅值设置为0
}
上一段源码,通过sobel算子计算出来的方向梯度值来计算当前点的梯度值。
最后当然就是该知道使用canny函数时的高低阈值参数怎么用了!
int m = _mag[j];//m为计算出来该点的梯度值
if (m > low) // 如果大于低阈值
{
int xs = _x[j]; // dx中 第i-1行 第j列
int ys = _y[j]; // dy中 第i-1行 第j列
int x = std::abs(xs);
int y = std::abs(ys) << CANNY_SHIFT;
}
//比当前的梯度幅值低阈值还低,直接被确定为非边缘
prev_flag = 0;
_map[j] = uchar(1); // 1 表示不属于边缘
然后就是在源码这个位置,填写的低阈值就有了他的用武之地了,通过计算出来的该点梯度值与低阈值做对比,是否为边缘。高阈值也类似,感兴趣的可以自己看源码
根据自己路径名改一下即可C:\yx\opencv\sources\modules\imgproc\src\canny.cpp文章来源:https://www.toymoban.com/news/detail-737231.html
到了这里,关于opencv中Canny的高低阈值参数简析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!