디렉토리
I. 서론
구덩이를 채우기 위해 계속합니다.
당신이 OpenCV의 프리젠 테이션, 학습 자습서, 코드 실제, 일반적인 오류 및 솔루션에 대한 학습과 관련된 다른 콘텐츠를보고 싶은 경우에, 당신은 직접 내 OpenCV의 카테고리를 볼 수 있습니다
【OpenCV의 系列】 : HTTPS : //blog.csdn.net/shuiyixin/article/category/7581855
당신이 더 많은 족장와 통신하기 위해, 컴퓨터 비전, OpenCV의, 기계 학습, 깊은 학습 및 기타 관련 기술에 대해 더 배우고 싶은 경우에, 지금 우리와 함께 할 다음 Fanger 웨이 코드를 스캔!
둘째, 에지 검출
(1) 엣지 검출은 무엇
우리가 먼저 이해에서 간단한 모양을 가지고 :
![](https://img-blog.csdnimg.cn/20200224215705527.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NodWl5aXhpbg==,size_46,color_FF85FF,t_70)
우리는 문자를 꺼내려면이지도를 들어, 내가 어떻게해야합니까? 우리는 파고를 얻기 위해 소프트웨어를 사용하여 다음과 같은 이미지를 얻을 것이다 :
![](https://img-blog.csdnimg.cn/20200227120027846.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NodWl5aXhpbg==,size_46,color_F75FFF,t_70)
우리는 사실, 이미지의 에지 검출의 예를 탐지 에지 그래서 우리는 (그런 사람들로) 과정의 가장자리의 프로세스 인스턴스의 이미지를 찾기 위해 실제로 매트.
우리가 그 것이다 지금 문제가 있음을, 어떻게 가장자리 사이의 구별?
우리는 각 인스턴스와 그것의 가장자리 주변의 픽셀 사이의 간격들은 일반적으로 더 큰 발견했다. 우리의 매트는, 인스턴스의 가장자리를 구별하는 픽셀 사이의 명백한 차이를 기반으로합니다.
따라서, 매트에 의하면, 화상 픽셀의 분명한 변화이다. 에지 이미지는 픽셀 위치는 일반적으로 이미지에 큰 변화가있다.
다음 우리는 화상의 화소를 나타내는 도면을 사용
![](https://img-blog.csdnimg.cn/20200227120917916.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NodWl5aXhpbg==,size_36,color_FFF75F,t_70)
우리는 이미지 픽셀의 위치에서의 상당한 변화를 찾아 이미지의 기울기의 정도는 수단 큰 것을 큰 기울기의 절대 값. 이 원칙은 우리가 몇 운영자에 대해 이야기하기 전에 일관 소벨 연산자는,이 위치를 계산하는 것입니다 :
이 이야기는 매우 그것을 만지고 느낄 수 있나요? ? ?
이 문제를 알고, 지금 우리는 그것의 에지 검출보다 공식적인 정의를 봐!
엣지 검출 화상 처리 및 컴퓨터 비전의 근본적인 문제는, 엣지 검출 화상 식별 번호의 목적은 명백 휘도 변화 점 것이다. 이미지 속성에 중대한 변화는 일반적으로 중요한 사건과 변화의 특성을 반영합니다.
(2) 엣지 검출 연산자
上面讲到,Sobel 算子可以用于边缘检测,那除了Sobel算子,还有那些算子能用于边缘检测呢?
这个问题我想大家应该比较容易回答了,我们之前学的三个算子都能用于边缘检测:
Sobel算子、Scharr算子、Laplance算子
除了这三个,我们今天再给大家讲一个算子,Canny算子。
三、Canny算子
1、讲解
接下来,我们来说一个新的算子Canny算子。
Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。它包括如下五个步骤:
1.应用高斯滤波来平滑图像,目的是去除噪声
2.找寻图像的强度梯度(intensity gradients)
3.应用非最大抑制(non-maximum suppression)技术来消除边误检(本来不是但检测出来是)
4.应用双阈值的方法来决定可能的(潜在的)边界
5.利用滞后技术来跟踪边界
接下来,我们来详细讲解一下每一个步骤:
1.图像平滑
图像平滑就是让图像之间的像素差距更小一些,能够更好地提取特征更加明显的边缘,所以图像平滑的目的就是去除部分噪声。
而图像平滑操作,我们思考一下,不就是让挨着的像素之间差距变小,图像模糊的作用不就是这样吗?所以图像平滑操作就是进行图像模糊操作,而我们最常用的模糊操作,是高斯模糊。
![](https://img-blog.csdnimg.cn/20200227170514280.png)
世上最帅的男人,没有之一!
科普一下下,高斯模糊不是高斯提出来的!
高斯模糊用的kernel是正态分布,正态分布也叫高斯分布。这是高斯模糊这个名字的由来。不是因为高斯提出的。甚至,高斯分布也不是高斯提出的,只是用他命名。高斯分布的提出者是棣莫佛和拉普拉斯,那个定理叫做棣莫佛-拉普拉斯定理。
但是这丝毫不会影响我们数学人对高斯的推崇。也不会影响我们数学人对任何一个在数学史上贡献自己一生的人致以最崇高的敬意。
言归正传,下面这个示例是一个5×5的kernel。
2.寻找图像强度梯度
Canny算法的基本思想是寻找一幅图像中灰度强度变化最强的位置。所谓变化最强,即指梯度方向。平滑后的图像中每个像素点的梯度可以由Sobel算子(一种卷积运算)来获得(opencv中有封装好的函数,可以求图像中每个像素点的n阶导数)。首先,利用如下的核来分别求得沿水平(x)和垂直(y)方向的梯度G_X和G_Y。
Sobel算子,我们很熟悉了,如果大家还有疑问,可以看这篇博客:
【opencv学习笔记】018之Sobel算子与Scharr算子:https://blog.csdn.net/shuiyixin/article/details/104484635
3.消除边误检
这一步的目的是将模糊的边界变得清晰(sharp)。通俗的讲,就是保留了每个像素点上梯度强度的极大值,而删掉其他的值。对于每个像素点,进行如下操作:
a) 将其梯度方向近似为以下值中的一个:
(0,45,90,135,180,225,270,315)(即上下左右和45度方向)
b) 比较该像素点,和其梯度方向正负方向的像素点的梯度强度
c) 如果该像素点梯度强度最大则保留,否则抑制(删除,即置为0)
为了更好的解释这个概念,看下图:
图中的数字代表了像素点的梯度强度,箭头方向代表了梯度方向。以第二排第三个像素点为例,由于梯度方向向上,则将这一点的强度(7)与其上下两个像素点的强度(5和4)比较,由于这一点强度最大,则保留。
4.双阈值求可能边
经过非极大抑制后图像中仍然有很多噪声点。Canny算法中应用了一种叫双阈值的技术。即设定一个阈值上界和阈值下界(opencv中通常由人为指定的),图像中的像素点如果大于阈值上界则认为必然是边界(称为强边界,strong edge),小于阈值下界则认为必然不是边界,两者之间的则认为是候选项(称为弱边界,weak edge),需进行进一步处理。
5.边界跟踪
较高的亮度梯度比较有可能是边缘,但是没有一个确切的值来限定多大的亮度梯度是边缘多大又不是,所以 Canny 使用了滞后阈值。
滞后阈值(Hysteresis thresholding)需要两个阈值,即高阈值与低阈值。假设图像中的重要边缘都是连续的曲线,这样我们就可以跟踪给定曲线中模糊的部分,并且避免将没有组成曲线 的噪声像素当成边缘。所以我们从一个较大的阈值开始,这将标识出我们比较确信的真实边缘,使用前面导出的方向信息,我们从这些真正的边缘开始在图像中跟踪 整个的边缘。在跟踪的时候,我们使用一个较小的阈值,这样就可以跟踪曲线的模糊部分直到我们回到起点。
2、API
接下来我们讲一下API
void Canny(
InputArray src,
OutputArray edges,
double threshold1,
double threshold2,
int apertureSize = 3,
bool L2gradient = false
);
函数参数含义如下:
(1)InputArray类型的src ,输入图像。
(2)OutputArray类型的edges,输出边缘图;单通道8位图像,其大小与图像相同。
(3)double类型的threshold1,滞后过程的第一个阈值。
(4)double类型的threshold2,滞后过程的第二个阈值。
(5)int类型的apertureSize,Sobel运算符的孔径大小。
(6)bool类型的L2gradient,一个标志,指示是否应使用更精确的L2来计算图像渐变幅度(L2gradient=true),或者是否应使用默认的L1(L2gradient=false)。(注:这里的L2是平方和开根号,L1是绝对值求和,如下图)
3、代码展示
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img, src;
img = imread("E:/image/girl2.png");
if (!img.data)
{
cout << "could not load image !";
return -1;
}
imshow("【输入图像】", img);
GaussianBlur(img, img, Size(5, 5), 0, 0);
Canny(img, src, 115, 255);
imshow("【输出图像】", src);
waitKey(0);
return 0;
}
4、执行结果
![](https://img-blog.csdnimg.cn/20200224215705527.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NodWl5aXhpbg==,size_46,color_FF85FF,t_70)
![](https://img-blog.csdnimg.cn/20200227175327955.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NodWl5aXhpbg==,size_46,color_F78FFF,t_70)
如果我们不使用模糊操作,得到的结果如下:
![](https://img-blog.csdnimg.cn/20200227175443581.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NodWl5aXhpbg==,size_46,color_FF78FF,t_70)
我们能够发现,如果我们模糊了之后,能够更好的提取我们需要的边缘,去掉一些不太关注的边缘,提取到的边缘更好。
大家也可以自己尝试一下呀,一定要多做练习!