OpenCV计算机图像视觉基础学习笔记12——应用:Canny边缘检测

继续学习。


理论知识

Canny边缘检测算法最早在1986年提出,它是一种很好的边缘检测方法,也是很常用,很实用的边缘检测方法。目前现代的很多边缘检测应用中都采用了Canny算法。

它的使用方法也很简单。

  • 高斯模糊 作用是对图像进行降噪,将可能影响算法的点去掉
  • 灰度转换
  • 计算梯度(SobelScharr
  • 非最大信号抑制
  • 高低阈值输出二值图像

非最大信号抑制是一步新的操作,做这个操作的原因是边缘只能有一个,如果存在多个边缘则只能留下一个。为了清晰起见只留下信号最强的边缘,将其他边缘消除。做法很简单,判断像素点在切向和法向是否为最大,如果不是则消除。

高低阈值是什么?我们做完非最大信号抑制之后就已经能得到一个边缘分明的图像了,但即使这样仍然不能达到对结果图像的要求。我们设定一个高阈值和低阈值,大于高阈值的保留,小于低阈值的舍弃,在中间范围的部分要做一个阈值连接操作。靠近高阈值的按保留做,靠近低阈值的按舍弃做。

浅谈非最大信号抑制

非最大值抑制能帮助保留局部最大梯度而抑制所有其他梯度值。这意味着只保留了梯度变化中最锐利的位置。通过前面的讨论我们可以知道,上图所示操作是一种体现在xy方向上的梯度差异。(这不就是Sobel算子吗)没有见过的是最下面的θ,它等于一个反三角函数。这个函数又由Gy和Gx的大小确定。它叫做梯度幅值,代表梯度的具体方向。取值范围看下图。

梯度角度θ范围从弧度-π到π,然后把它近似到四个方向,分别代表水平,垂直和两个对角线方向(0°,45°,90°,135°)。可以对它进行一下分割,落在每个区域的梯度角给一个特定值,代表四个方向之一。

它的算法如下:

  1. 比较当前点的梯度强度和正负梯度方向点的梯度强度。
  2. 如果当前点的梯度强度和同方向的其他点的梯度强度相比较是最大,保留其值。否则抑制,即设为0。比如当前点的方向指向正上方90°方向,那它需要和垂直方向,它的正上方和正下方的像素比较。

高低阈值输出二值图像

T1, T2为阈值,凡是高于T2的都保留,凡是小于T1都丢弃,从高于T2的像素出发,凡是大T1而且相互连接的,都保留。最终得到一个输出二值图像。

推荐的高低阈值比值为 T2: T1 = 3:1/2:1其中T2为高阈值,T1为低阈值。

简单实践

相关API:cv::Canny

1
2
3
4
5
6
7
8
Canny(
InputArray src, // 8-bit的输入图像
OutputArray edges,// 输出边缘图像, 一般都是二值图像,背景是黑色
double threshold1,// 低阈值,常取高阈值的1/2或者1/3
double threshold2,// 高阈值
int aptertureSize,// Soble算子的size,通常3x3,取值3
bool L2gradient // 选择 true表示是L2来归一化,否则用L1归一化,一般用L1

对边缘的检测效果还是很不错的。虽然加了trackbar,但是发现调还不如不调效果好。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat src, gray_src, dst;
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny Result";

void Canny_Demo(int, void*) {
Mat edge_output;
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);

//dst.create(src.size(), src.type());
//src.copyTo(dst, edge_output);
imshow(OUTPUT_TITLE, ~edge_output);
}

int main() {
src = imread("D:/pic4.png");
if (!src.data) {
cout << "could not load image..." << endl;
return -1;
}

char INPUT_TITLE[] = "input image";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);

cvtColor(src, gray_src, CV_BGR2GRAY);
createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
Canny_Demo(0, 0);

waitKey(0);
return 0;
}

参考文章

https://www.cnblogs.com/mightycode/p/6394810.html

https://www.cnblogs.com/pacino12134/p/9877971.html


-------------本文结束,感谢您的阅读转载请注明原作者及出处-------------


本文标题:OpenCV计算机图像视觉基础学习笔记12——应用:Canny边缘检测

文章作者:Shawn Zhou

发布时间:2019年08月31日 - 10:08

最后更新:2019年08月31日 - 11:08

原始链接:http://shawnzhou.xyz/2019/08/31/19-08-31-02/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

知识无价,码字不易。对您有用,敬请打赏。金额随意,感谢关心。
0%