最近小可爱们有没有等我们的技术推等到望穿秋水啊?大家日思夜想的技术推来啦。今天我们来一起学习一下opencv里面一个重要方面:边缘检测。
01.什么是边缘检测
边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。
这些包括:
(i)深度上的不连续
(ii)表面方向不连续
(iii)物质属性变化
(iv)场景照明变化
边缘检测是图像处理和计算机视觉中,尤其是特征提取中的一个研究领域。图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。
02.边缘检测的步骤
它的步骤简单来说可以分成三种:
(1)滤波:边缘检测的 算法 主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测的性能。常见的滤波方法主要有 高斯滤波,即采用离散化的高斯函数产生一组归一化的高斯核(具体见“高斯滤波原理及其编程离散化实现方法”一文),然后基于高斯核函数对图像灰度矩阵的每一点进行加权和(具体程序见下文)
(2)增强 :增强边缘 的基础是确定图像各点邻域强度的变化值。增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。在具体编程实现时,可通过计算梯度幅值来确定。
(3)检测: 经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是我们想要的找的边缘点,所以应该采用某种方法来对这些点进行取舍。在实际工程中,常用的方法是 通过阈值化方法来检测。
03.Canny算子
Canny算子在opencv中是最常用来进行边缘检测的,接下来我们就简要介绍一下它。
Canny边缘检测算子是John F.Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计算理论,解释了这项技术是如何工作的。Canny边缘检测算法以Canny的名字命名,被很多人推崇为当今最优的边缘检测的算法。
其中,Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的三个主要评价标准是:
1 低错误率:标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报
2 高定位性:标识出的边缘要与图像中的实际边缘尽可能接近
3 最小响应:图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘
04.如何利用Canny算子进行检测
利用Canny算法进行图像的边缘检测:
1 void Canny (InputArray image,OutputArray edges , double threshold1,
2 Threshold2 ,int apertureSize = 3,bool L2gradient = false);
注解:
·第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像.
·第二个参数,OutputArray类型edges,输出的边缘图,需要和源图片有一样的尺寸和类型.
·第三个参数,double类型threshold1,第一个滞后性阈值.
·第四个参数,double类理的threshold2,第二个滞后性阀值.
·第五个参数,int类型的apertureSize,表示应用Sobel算子的孔径大小,其有默认值3.
·第六个参数,bool类型的L2gradient,一个计算图像梯度幅值的标识,有默认值false.
(需要注意的是,这个函数阈值1和阈值2两者的小者用于边缘连接,而大者用来控制强边缘的初始段,推荐的高低阈值比在2:1到3:1之间)
05.函数实例
使用示例:
1 // 输入原始图
2 Mat src = inread (“1.jpg”)
3 Canny ( src , src , 3,9,3);
4 inshow (“[效果图]边缘检测”,src);
如上三句,就有结果出来,非常好用。
▲向上滑动
函数示例:
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
/*------------------------------
【1】Canny算子
---------------------------------*/
int main()
{
//载入原始图
Mat src = imread("1.jpg");
Mat src1 = src.clone();
//Mat src2 = src.clone();
//显示原始图
imshow("【原始图】Canny边缘检测", src);
/*----------------------------
// (1) 最简单的canny用法,拿到原图后直接用
-----------------------------------*/
Canny(src,src,150,100,3);
imshow("【效果图】Canny边缘检测", src);
/*---------------------------------------
//(2)高阶的canny用法,转成灰度图,降噪, 用Canny, 最后得到的边缘作为掩码,拷贝原 图到效果图上,得到 彩色的边缘图
----------------------------------*/
Mat dst, edge, gray;
//(1)创建与src 同类型和大小的矩阵
dst.create(src1.size(),src1.type());
//(2)将原图转换为灰度图像
cvtColor(src1,gray,CV_BGR2GRAY);
//(3)使用3*3内核来降噪
blur(gray,edge,Size(3,3));
//(4)运行Canny算子
Canny(edge,edge,3,9,3);
//(5)将g_dstImage内的元素设为0
dst = Scalar::all(0);
//(6)使用Canny算子输出的边源:
g_canny DetectEdges作为掩码,将g_srcImage拷到目标图g_dstImage中,
src1.copyTo(dst,edge);
//(7)显示效果图
imshow("【效果图】Canny边缘检测2", dst);
waitKey();
return 0;
}
示例图如下
原图是这样的
![fbe379dd5e81603250bb0d0efd87c114.png](https://i-blog.csdnimg.cn/blog_migrate/65ee750a10a1ce9441f64211987e923f.jpeg)
检测完后的效果图。
![a3bf668c3bb91d55774d9df7a0cee32e.png](https://i-blog.csdnimg.cn/blog_migrate/d8e4a5db9ece3265d968b5bb43d00664.jpeg)
可以看出这个算法非常细腻地把图里面的轮廓都给找出来了。
不过,有时候过于细腻也不好,这时候就需要调整参数或者采用其他算法,比如sobel算法和拉普拉斯算法。嘻嘻,这些就等下次再来介绍咯。
![aad7291e05209ce95b42948d714f42f5.png](https://i-blog.csdnimg.cn/blog_migrate/01d399eabdbe83d7f0c1e2c432da7941.jpeg)
文案/ 谢函瀚
排版/胡文博