opencv边缘检测的入门剖析(第七天)
---边缘检测概念理解---
边缘检测的理解可以结合前面的内核,说到内核在图像中的应用还真是多,到现在为止学的对图像的操作都是核的操作,下面还有更神奇的!
想把边缘检测出来,从图像像素的角度去想,那就是像素值差别很大,比如X1=20和X2=200,这两个像素差值180,在图像的显示就非常明显,这样图像的边缘不就体现出来了?但是问题来了,一幅图像给你,如果一个像素一个像素对比,
1.周围像素差别不大的怎么办?
2.周围相差很大,但是很多的怎么办?
3.怎么样才能更好地区别图像的边缘呢?
比如5-200比较肯定算一个边缘,但是200-200比较久不是边缘了。如果全部做对比的话有很多的问题存在,这只是一个简单的问题。

---范谈各种边缘检测---
从上面的分析可以得到,边缘检测->>>>>就是分离那些相差大的像素
如何分离像素,现在脑子里有个映像:利用核去处理图像!
A. Robert算子检测边缘:

x和y方向的算子
观察上诉的算子,可以发现和我们刚开始设想的一个一个比较差不多,比如本来比如X1=20和X2=40,这两个像素差值20,但是20体现不出来,所以用1,-1来增大这种差值,这其实解决了我们上诉遇到的第一点问题了,但是后面的两点依然没有解决。
具体的例子我们可以用opencv自带的API,addwight进行试验,把核改一下就行了。。。
Roberts算子检测方法对具有陡峭的低噪声的图像处理效果较好,但是利用roberts算子提取边缘的结果是边缘比较粗,因此边缘的定位不是很准确。
B. Sobel算子检测边缘:

X和Y方向

对X\Y两个方向的梯度进行合并
Sobel算子如果光从核上面去看,根本什么都不知道,我们得去看他的原理->>>>

他的原理就是利用导数求解边缘,我们知道像素差别大的时候那么它的切点越陡峭,那么这个时候就找到了边缘!具体程序怎么实现的,我还没弄懂,感觉是利用拉普拉斯变化之后再计算的,最后用一个算子近似代替。。。(个人YY)
Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果较好,sobel算子对边缘定位不是很准确,图像的边缘不止一个像素。
C. Laplacian算子检测边缘:

拉普拉斯算子

拉普拉斯边缘检测是通过二阶倒数,从上面的一阶倒数的理解就不难发现二阶倒数是怎么进行的了。
二阶倒数比一阶倒数的好处是在与受到周围的干扰小,其不具有方向性,操作容易,且对于很多方向的图像处理好。
Laplacian算子法对噪声比较敏感,所以很少用该算子检测边缘,而是用来判断边缘像素视为与图像的明区还是暗区。
C. Scharr算子检测边缘:
这个滤波是Sobel的升级版,原理是一样的,就是实现的近似代替不一样,说白了就事核改进了。。。

D. Canny算子检测边缘:
这是比较新的算法,运用的也是最广泛的。这个算法是在Sobel算法的基础上改进的,和Scharr不一样!
Canny的步骤是:1.给一张图片,先进行滤波消除干扰,滤波前面博客已经说明。
2.计算梯度(进行Sobel算子计算)。
3.非极大值抑制。
4.滞后阈值。
下面一届具体介绍->>>>
在opencv2.0的时候,直接调用API就帮你完成全部的工作,包含上面的四部。
现在opencv3.0滤波得自己操作,API完成了后三步操作。
这里在Sobel运行之后的基础上对图像的边缘进行了优化,哪些是优秀的,哪些是差的,在这里会处理。
---细谈边缘检测---
上面讲到Canny的非极大值抑制和滞后阈值,其中这两点是这个算法的核心!
非极大值抑制:
从字面上的理解就是从一群数据中找到真正的极大值,对于不是极大值的省略或者抑制显示。
我们来想一下,Sobel算子计算的值就是边缘的值吗?1.算子是固定的,那就有很大的几率会计算到不是边缘的数据。
2.计算的结果不会省略不好的点,也不会去加强好的点,所以显示就不明显。
我们的目的就是改进上面两个点,对于第一个点,我们得比较那些计算的点进行比较,把不好点舍去--->>>
以前在神经网络那篇博文里提到过“梯度”的概念,就是数据下降或者上升最快的方向,简单的说就是求导切线的方向!
试想一下我们在这个方向上找最大和最小值是最快最准确的,这个具体原因神经网络那篇博文说过了,可以去看看。

通过计算我们得到了θ的值在[-π/2,+π/2]区间,然后我们就可以比较在这个方向上的G和左右G1、G2的大小,当G>G1、G2的时候,那就说明这个G就是局部极大值,从而保留下来:

例如:G0的θ是45度,那么在它的梯度方向来对比它是不是最大值,如果是的话那就说明它是局部极大值->判断G0和(G3、G6)的大小关系!G0 = G0>G3&&G0>G6? G0:0;
上面的方法是第一代非极大值抑制算法,缺点是当 θ!=0、45、90、180 时,那么旁边的八个值就不在θ的梯度上,就没办法去做比较了,这时候出现第二代算法--->>>
插值法运用在非最大值抑制算法中:

插值法:就是y=kx+b的插值公式,比如:X1和X2中间想插一点X,X = X1 + k(X2-X1)或者X= k*X1 +(1-k)X2 当然插值法还有其它形式,不过两点的线性插值比较简单的。这里使用第二者!
上面的图形是当 |Gy|>|Gx| && Gx*Gy>0 的情况。前者保障靠近y轴,后者保证θ>0.
注释:在有的文章上看的和我说的相反,按照数学知识应该是这样的啊,具体原因我也不知道了。
令 k = |Gy/Gx|
G23 = k*G2 + (1-k)*G3;
G67 = k*G6 + (1-k)*G7;
G0 = G0>G23 && G0>G67 ? G0:0;或者这里可以突出重点给定G0的值G0 = G0>G23 && G0>G67 ? 200:0;
opencv的源码就是使用这种方法的,大家可以参考源码:
void NonMaxSuppress(int*pMag,int* pGradX,int*pGradY,SIZE sz,LPBYTE pNSRst)
{
LONG x,y;
int nPos;
// the component of the gradient
int gx,gy;
// the temp varialbe
int g1,g2,g3,g4;
double weight;
double dTemp,dTemp1,dTemp2;
//设置图像边缘为不可能的分界点
for(x=;x<sz.cx;x++)
{
pNSRst[x] = ;
pNSRst[(sz.cy-)*sz.cx+x] = ; }
for(y=;y<sz.cy;y++)
{
pNSRst[y*sz.cx] = ;
pNSRst[y*sz.cx + sz.cx-] = ;
} for (y=;y<sz.cy-;y++)
{
for (x=;x<sz.cx-;x++)
{
nPos=y*sz.cx+x;
// if pMag[nPos]==0, then nPos is not the edge point
if (pMag[nPos]==)
{
pNSRst[nPos]=;
}
else
{
// the gradient of current point
dTemp=pMag[nPos];
// x,y 方向导数
gx=pGradX[nPos];
gy=pGradY[nPos];
//如果方向导数y分量比x分量大,说明导数方向趋向于y分量
if (abs(gy)>abs(gx))
{
// calculate the factor of interplation
weight=fabs(gx)/fabs(gy);
g2 = pMag[nPos-sz.cx]; // 上一行
g4 = pMag[nPos+sz.cx]; // 下一行
//如果x,y两个方向导数的符号相同
//C 为当前像素,与g1-g3 的位置关系为:
//g1 g2
// C
// g4 g3
if(gx*gy>)
{
g1 = pMag[nPos-sz.cx-];
g3 = pMag[nPos+sz.cx+];
}
//如果x,y两个方向的方向导数方向相反
//C是当前像素,与g1-g3的关系为:
// g2 g1
// C
// g3 g4
else
{
g1 = pMag[nPos-sz.cx+];
g3 = pMag[nPos+sz.cx-];
}
}
else
{
//插值比例
weight = fabs(gy)/fabs(gx);
g2 = pMag[nPos+]; //后一列
g4 = pMag[nPos-]; // 前一列
//如果x,y两个方向的方向导数符号相同
//当前像素C与 g1-g4的关系为
// g3
// g4 C g2
// g1
if(gx * gy > )
{
g1 = pMag[nPos+sz.cx+];
g3 = pMag[nPos-sz.cx-];
} //如果x,y两个方向导数的方向相反
// C与g1-g4的关系为
// g1
// g4 C g2
// g3
else
{
g1 = pMag[nPos-sz.cx+];
g3 = pMag[nPos+sz.cx-];
}
}
//--线性插值等价于dTemp1 = g1 + weight*(g2-g1)--//
dTemp1 = weight*g1 + (-weight)*g2;
dTemp2 = weight*g3 + (-weight)*g4;
//当前像素的梯度是局部的最大值
//该点可能是边界点
if(dTemp>=dTemp1 && dTemp>=dTemp2)
{
pNSRst[nPos] = ;
}
else
{
//不可能是边界点
pNSRst[nPos] = ;
}
}
}
}
}
在论文中海油一个改进的插值,用二次插值代替一次插值,学过数值分析的都知道,一次插值在直线很好,但是在曲线不好,当然二次插值也不能消除很多误差,当然海油牛顿插值等等。。。
这是当Gx和Gy同号的情况,另一种情况自己想一下就行了。


二次插值相比较一次插值的优点是:不用考虑哪个哪个具体的角度。其实很多人都提到了0、45、90、180的角度划分,我这里没有提到,原理是一样的,我感觉直接做就好了,没必要再去弄个中间变量过度一下,可能为了理解吧。
滞后阈值:
1. T1, T2为阈值,凡是高于T2的都保留,凡是小于T1都丢弃。
2.如果介于T1和T2之间的话,判断是否连接T2,如果没连接T2那就删除。
3.T1和T2比例最好1:2/1:3
这里说明一下第二点:
A.我们的目的是找到最大边缘变化。
B.并且保证边缘显示效果很好。
对于A来说,我们非最大值抑制已经找到部分最大值,现在用T2再进行一遍,已经很好的达到我们A目的了。
对于B来说,用T1去滤去可能不是最大值的点,现在用第二点来加强显示,在T2附近的保留,不在的都删除(意思就是在最小值附近)。
看下面这个例子,T1=2,T2=9 用核3X3去找T2附近的值,那就表示只有6个值可以保留,其他值都将被删除。
第一步:整个图像去找T>T2和T<T1的值,删除或者保留,并且标记记录。
第二步:在上一步记录的最大值附近寻找存在的值,直接删除或者保留。

参考:《自适应Canny算法研究及其在图像边缘检测中的应用_金刚》
http://blog.csdn.net/kezunhai/article/details/11620357
opencv边缘检测的入门剖析(第七天)的更多相关文章
- 【图像处理】OpenCV+Python图像处理入门教程(七)图像形态学操作
图像形态学主要从图像内提取分量信息,该分量信息通常对表达图像的特征具有重要意义.例如,在车牌号码识别中,能够使用形态学计算其重要特征信息,在进行识别时,只需对这些特征信息运算即可.图像形态学在目标视觉 ...
- [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...
- Docker入门教程(七)Docker API
Docker入门教程(七)Docker API [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第七篇,重点介绍了Docker Registry API和 ...
- Photoshop入门教程(七):蒙版
学习心得:蒙版在Photoshop中也是很常用的,学会使用蒙版,可以提高图像处理能力,并且可以保护原片不被破坏,建议多使用一些蒙版. 蒙板是灰度的,是将不同灰度色值转化为不同的透明度,并作用到它所在的 ...
- c#开发移动APP-Xamarin入门剖析
原文:c#开发移动APP-Xamarin入门剖析 剖析应用程序 Phoneword这个项目是.net标准库项目,它包含所有的共享代码和共享UI. Phoneword.Android这个项目包含Andr ...
- Elasticsearch7.X 入门学习第七课笔记-----Mapping多字段与自定义Analyzer
原文:Elasticsearch7.X 入门学习第七课笔记-----Mapping多字段与自定义Analyzer 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处 ...
- OpenCV——边缘检测入门、Canny边缘检测
边缘检测的一般步骤: 最优边缘检测的三个评价标准: 低错误率:表示出尽可能多的实际边缘,同时尽可能地减少噪声产生的误报: 高定位性:标识出的边缘要与图像实际边缘尽可能接近: 最小响应:图像中的边缘只能 ...
- OpenCV入门笔记(七) 文字区域的提取
https://blog.csdn.net/huobanjishijian/article/details/63685503 前面我们已经学了一些OpenCV中基本的图片处理的知识,可以拿来做一些小应 ...
- OpenCV边缘检测的详细参数调节
1. findCountours 转载于http://blog.sina.com.cn/s/blog_7155fb1a0101a90h.html findContours函数,这个函数的原型为: &l ...
随机推荐
- bug20170125
1s定时请求接口,接口不响应(接口挂掉),浏览器崩溃
- 杭电oj2001-C语言
题目 题目 Problem Description 输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离. Input 输入数据有多组,每组占一行,由4个实数组成,分别表示x1,y1,x ...
- 抓老鼠 codeForce 148D - Bag of mice 概率DP
设dp[i][j]为有白老鼠i只,黑老鼠j只时轮到公主取时,公主赢的概率. 那么当i = 0 时,为0 当j = 0时,为1 公主可直接取出白老鼠一只赢的概率为i/(i+j) 公主取出了黑老鼠,龙必然 ...
- 第二百七十六节,MySQL数据库,【显示、创建、选定、删除数据库】,【用户管理、对用户增删改查以及授权】
MySQL数据库,[显示.创建.选定.删除数据库],[用户管理.对用户增删改查以及授权] 1.显示数据库 SHOW DATABASES;显示数据库 SHOW DATABASES; mysql - 用户 ...
- CentOS7防止CC攻击防止SSH爆破采取的措施
准备工作 1.检查firewalld是否启用 #如果您已经安装iptables建议先关闭 service iptables stop #查看firewalld状态 firewall-cmd --sta ...
- 在Docker中运行crontab
在把自己的项目通过Docker进行打包时,由于项目中用到了crontab,不过使用到的基础镜像python:3.6-slim并没有安装这项服务,记录下在镜像中安装和配置crontab的过程. Dock ...
- Servlet基本操作
一.Servlet的请求流程 web项目中的web.xml文件配置为: <servlet> <!--别名--> <servlet-name>Hello</se ...
- 黑电-逻辑地址-0X4EB9FDE3- %o %d %x
****************************************************************************** 编程语言通常规定是以0开头的数字是八进制数 ...
- 获取js 文件传递的参数并使用json2进行json数据转换
主要的技术就不用详细进行介绍了,就是使用js文件进行参数的传递,用途有一下几个: 1,进行js的版本控制. 2,获取参数并,进行一些额外功能的添加(比如使用js 进行用户验证,设计开发API (一些开 ...
- 如何安装Genymotion模拟器
我们在进行App测试的时候,除了使用真机进行测试,有时候还需要借助模拟器来进行测试,那么Android SDK本身给我们提供了一个原生态的模拟器,但是由于启动太慢,性能太差,逐渐被大家放弃了,那么还有 ...