canny边缘检测_opencv图像边缘检测

很多人在学习图像处理的时候,都会接触到边缘检测算法。但是,大部分人可能都只是会调用算法,而不知道算法的原理,也不知道边界检测之后应该怎么办。不知道怎么应用边缘检测的结果,感觉不知所措,只是肉眼可见检测的结果,而不知道下一步应该怎么处理。边缘检测只是图像处理的中间步骤,其实我们进行图像处理的目的是要提取出想要的特征,然后将特征表达出来。比如,提取图像的轮廓特征,矩特征等基本特征,还有一些高级特征也可以通过边缘检测实现。又如,可以将边缘检测的结果作为特征点,然后利用这些特征点实现匹配、定位、识别、分类等操作。

图像边缘检测的目的是目标对象与背景,为下一步的处理做准备,比如,可以利用边缘检测的结果对图像进行分割;可以利用边缘检测的结果提取图像的特征;可以用边缘检测的结果对特定区域进行定位等等。常用的边缘检测方法有很多,如sobel算子、Roberts算子、Prewitt算子、Laplacian算子、Canny算子、Scharr算子、高斯拉普拉斯算子(LOG,Laplacian of Gaussian)、高斯差分算子(DOG)等。不管哪种算子,其中最终的原理都差不多,就是利用图像的梯度信息。

图像的梯度定义的是图像的变化幅值和方向。这个概念在图像处理中非常重要,大部分的图像处理都离不开图像梯度的概念。要说清楚图像的梯度,先要了解图像的微分和差分计算方法。按照高等数学上学的求导与微分的计算方法,图像是二维离散函数,计算方法也是一样的。设图像为f(x,y),

一阶微分的计算公式非常简单:

23d23a7fdb050e4fdc47226fe00851d8.png

离散化之后就是图像的差分计算方程:

2823655d1471531e42618f08b3edf366.png

其中,梯度方向就是 :

f308dc2304ddd8140be81c1981728c31.png

梯度幅值就是 :

257923e42502fabb6beb6c99fa99dfdd.png

上面的公式看起来好像有点复杂,其实对于图像而言,就是对应的位置像素值的加减运算。如果在说简单一点,这些也可以弄成一个模板,然后与图像进行卷积运算。比如,Roberts算子计算如下:

0903695f74f5644868a99d215813c5bb.png

其实Roberts算子也就是计算了2x2区域的对角线像素值之差。

sobel算子计算如下:

3a566784272e9a17ec3df918d63a4176.png

sobel算子的计算模板如下:

6dc364d712618365d4fd3352c85cc83b.png

其他的边界检测算子类似,Laplacian算子是计算的二阶差分,LOG算子是先对图像进行高斯滤波,然后在利用拉普拉斯算子根据二阶导数的过零点来检测图像的边界。DOG算子就是高斯差分,其边界检测结果和LOG差不多,只不过计算比LOG快一些。Canny算子是比较有名的边缘检测算子,这个算子先用高斯滤波器对图像进行滤波,去除图像噪声;然后得到图像的梯度强度和方向;再对梯度进行“非极大抑制”,并且对抑制结果取两次阈值,Th1和Th2,一般Th1=0.4Th2 ;最后链接边缘得到检测结果。

在opencv里面实现了部分边缘检测函数,下面以具体的代码看一下这些边界检测函数怎么实现的,具体的效果在这里不讨论,因为针对不同的图像需要调整不同的参数,才能够达到理想的效果,这里只是学会如何使用这些函数。

#include "iostream"
#include "opencv2opencv.hpp"
 
 
using namespace std;
using namespace cv;
 
int main(int argc, char ** argv)
{
 Mat src = imread("e:img1.ppm", 1);
 namedWindow("原图", 0);
 imshow("原图", src);
 Mat srcGray;
 cvtColor(src, srcGray, COLOR_BGR2GRAY);
 namedWindow("原图转成灰度图", 0);
 imshow("原图转成灰度图", srcGray);
 Mat cannyResult;
 Canny(srcGray, cannyResult, 50, 120);
 namedWindow("canny边界", 0);
 imshow("canny边界", cannyResult);
 
 Mat grad_x, grad_y;
 Mat abs_grad_x, abs_grad_y, sobelDst;
 
 
 //求 X方向梯度 
 Sobel(srcGray, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
 convertScaleAbs(grad_x, abs_grad_x);
 namedWindow("X方向Sobel", 0);
 imshow("X方向Sobel", abs_grad_x);
 
 //求Y方向梯度 
 Sobel(srcGray, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
 convertScaleAbs(grad_y, abs_grad_y);
 namedWindow("Y方向Sobel", 0);
 imshow("Y方向Sobel", abs_grad_y);
 
 //合并梯度(近似) 
 addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, sobelDst);
 namedWindow("整体方向Sobel", 0);
 imshow("整体方向Sobel", sobelDst);
 
 Mat gaussBlur;
 GaussianBlur(src, gaussBlur, cv::Size(3, 3),0, 0, cv::BORDER_DEFAULT);
 Mat LOGDst;
 // 拉普拉斯变换 
 Laplacian(src, LOGDst, CV_16S, 3);
 convertScaleAbs(LOGDst, LOGDst);
 namedWindow("LOG", 0);
 cv::imshow("LOG", LOGDst);
 
 Mat dst;
 GaussianBlur(src, dst, Size(3, 3), 0);
 Mat img_DoG = src - dst;
 normalize(img_DoG, img_DoG, 255, 0, NORM_MINMAX);
 namedWindow("DoG", 0);
 cv::imshow("DoG", img_DoG);
 waitKey(0);
 return 0;
}

1039b5d0dfcaad3eb51e0be698267a46.png

图1 边缘检测效果

边缘检测有很多用途,这里只是展示了怎么使用这些函数。学会调用这些函数,知道每个函数的检测原理对以后的特征检测是非常有用的。这里实现了部分函数,其他的检测方式有兴趣的可以自己去试一试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值