opencv中Canny的高低阈值参数简析

void Canny( InputArray _src, OutputArray _dst,
                double low_thresh, double high_thresh,
                int aperture_size, bool L2gradient )

相信很多同学在使用Canny函数的时候只知道高阈值和低阈值调高或者调低有什么用,就像下面的总结一样:

  1. 低于阈值1的像素点会被认为不是边缘;
  2. 高于阈值2的像素点会被认为是边缘;
  3. 在阈值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中

a700e5cbe3874a428668c97bb4956af2.png

 

gif.latex?%5Ctiny%20Gx%20%3D%20%5Bf%28x+1%2Cy-1%29%20+%202f%28x+1%2Cy%29%20+%20f%28x+1%2Cy+1%29%5D%20-%20%5Bf%28x-1%2Cy-1%29%20+%202f%28x-1%2Cy%29%20+%20f%28x-1%2Cy+1%29%5D

gif.latex?%5Ctiny%20Gy%20%3D%20%5Bf%28x-1%2Cy-1%29+%202f%28x%2Cy-1%29%20+%20f%28x+1%2Cy-1%29%5D%20-%20%5Bf%28x-1%2C%20y+1%29%20+%202f%28x%2Cy+1%29%20+%20f%28x+1%2Cy+1%29%5D

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

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值