白话文讲计算机视觉-第六讲-轮廓检测算法


大家好,欢迎收听小木的第六讲,第六讲我们主要讲的内容是轮廓检测。说道轮廓检测。轮廓怎么检测呢,那么我们就要引入一个轮廓检测算法:

这个算法是日本的铃木桑发明的。这位日本人写了一篇论文,叫做:

Topological structural analysis of digitized binary images by border following,

百度文库上面有下载地址:

https://wenku.baidu.com/view/6cb52ede360cba1aa811dad5.html

说道百度文库,我要吐槽一下,我觉得CNKI上面的文章都不如百度文库上面网友写的好。今天吐槽的话题太多了,首先说一下天朝不合理的科研评优制度。现在考一个博士,比如哈工大、同济,大连理工等学校竟然要一篇SCI,同济甚至是2篇。我就想请问你们是在TMD考老师呢还是在考学生?你们同济可能有设备,有经费。但是其它普通学校有吗?你以为学生是巧妇?巧妇都难做无米之炊,你们要求真是无理。我就请问你们985学校的筛选制度,真的能筛选出NB的学生吗?这个升学坑爹。还有坑爹的是大家喜欢到知网去灌水,结果知网上面全是垃圾文,而且瞎乱引用,引用次数高的还不一定是好的。所以大家找一篇好文实在是太TMD难了。我就想请问,什么国家奖学金那几万块钱,真的这么重要么,就不能发几篇好文章上去吗?

说完这个,还得吐槽一下这个日本人铃木先生,铃木先生这篇文章是1985年写的,也就是说我们现在是2018年,我们足足落后了小日本20多年。美帝就更不用说了。所以我想对现在的年轻人说,我们历史必须铭记,但是不是无脑黑,也不能无脑当HJ。这点应该学习罗永浩老师,把小日本的好东西都学到手,这个才是最重要的。不能学洁洁良,更不能学那些水军。如果认为我说的对,你们必须得转发我的文章!

好了,废话说完了,进入正题。这个日本人发明了一种能够检测轮廓的算法,这个轮廓检测是在一张只有1和只有0的二值图片中执行的,而这个算法定义了几个概念:

(1)框架:框架就是指图片的第一列、最后一列、第一行、最后一行像素,这四个长条组成的一个矩形框框,我们这些点是黑点,也就是0。

(2)背景:除了框架之外,和框架属于同一层级的像素点,这些点也是黑点,也就是0。

(3)外轮廓:外轮廓就是指包裹了一堆白点的最外围的白点。

(4)内轮廓:内轮廓是指在包裹了一堆白点的最内部的白点。

用一张图片表示会很清晰:


在这张图片中,S1是背景,也是框架层。S2是包裹的一堆白点,这堆白点的最外层和框架层紧密相连,B1就是S2的外轮廓,B2就是S2的内轮廓。

那么我们怎么用计算机判断一张图片上的点是外轮廓还是内轮廓呢?

那么就得进行如下的步骤:

(1)首先,我们设定外部框架的边界值NBD1

(2)接着忽略最外层的框架,然后从图片的第二行的最左侧开始,判断:

如果这个数字是1,并且它的左侧的像素是0,那么我们令(i,j)为这个像素,然后令(i2,j2)=(i,j-1)为它左侧的像素(如果是第一次运算,那么坐标就是(2,2),它要是1(2,1)0,那么(i,j)=(2,2)(i2,j2)=(i,j-1)=2,1))。然后我们令NBD=NBD+1,并且认为这个点是外轮廓点。

如果这个数字是大于等于1的,并且它的右侧像素是0,那么我们令(i,j)为这个像素,然后令(i2,j2)=(i,j+1)为它右侧的像素。(如果是第一次运算,那么坐标就是(2,2),它要是1(2,3)0,那么那么(i,j)=(2,2)(i2,j2)=(i,j+1)=2,3)),并且认为这个点是内轮廓点。

如果是其它的情况,那么,令直接跳到最后一步。

(3)下一步是判断这个点到底是内轮廓还是外轮廓,我们用这个表格来判断:

 

这里面B’表示的是上一个按照我们这个步骤走的点是什么轮廓。B表示我们当前的点是什么轮廓。如果这是第一次,没有上一次的点,那么直接认为是外轮廓就好了。

(4)从点(i,j)开始,它的邻近地方有8个点(3*3)的格子之内,然后我们以(i2,j2)点为起始点,然后顺时针的沿着这8个点移动,一直走走走走,唉,发现了一个不为0的像素点,并且令这个点为(i1,j1)。如果这8个点都为0的话,令中心点(i,j)-NBD,然后直接跳到最后一步。

(5)如果(i1,j1)存在的话,那么我们令(i2,j2)=(i1,j1)(i3,j3)=(i,j)

(6)然后我们从点(i3,j3)开始,以(i2,j2)为起始点,然后逆时针移动遍历(i,j)邻近地方的8个点。找到第一个不为0的点((i2,j2)这个点不算)。然后令它为(i4,j4)。注意这里肯定不会存在没有不为0点的情况,因为(i3,j3)=(i,j),上一次循环都循环一次了,没有早退出了。

(7)然后我们判断:如果(i3,j3)前面的点(i3,j3+1)0的话,那么我们把(i3,j3)这个点的像素值赋予-NBD

如果(i3,j3)点前面的点不为0,且(i3,j3)这个点的像素为1的话,那么把(i3,j3)的像素值赋予NBD

如果是其它情况的话,这个值保持不变。

(8)判断,如果(i4,j4)=(i,j)也就是我们最开始的那个值,且(i3,j3)=(i1,j1),那么我们跳到最后一步。如果要不符合条件,我们返回到(6)继续计算直到满足条件。

(9)我们回到我们最开始选择的那个点,也就是(i,j)然后我们往右边移动一格,如果已经到达末尾了,换到下一行的左边。如果我们于(i,j)那点的像素不为1的话,我们令LNBD等于(i,j)那点的像素的绝对值。

这九步,我们就把轮廓计算完毕了。在铃木桑的论文中,它举了一个例子来说明这个算法,如下所示:

 

这个是它最后得到的结果,但是我有点不信,下面我按照它同样的算法,自己手算了一遍:

 

 

我的最后结果是分为4部分,4个外轮廓,没有内轮廓,而铃木的是5部分,有一个内轮廓。我认为我的里面那个-3不是内轮廓,因为内轮廓应该是八方向都封闭起来的,而这两个-3只有2个方向是封闭,两个方向直接和背景连接。所以我认为是外轮廓。

谁对谁错我不好说,你们自己分析,然后对这两个人的案例对错评论一下,告诉我哈!

这样,我们的轮廓就检测完毕了。我们用OPENCV检测也非常的简单:

(1)首先我们导入一张图片。

(2)将图片二值化变成黑白图像

(3)运用轮廓搜索算法找出轮廓

(4)显示轮廓。

代码如下:

import cv2

import numpy as np

 

#导入图片

img = cv2.imread("D:/xiaomu/opencv6-1.jpg")

#显示图片

cv2.imshow("orgin",img)

#定义一个卷积核的尺寸

kernel = np.ones((3,3))  

#导入图片,进行开闭运算去噪声

img=cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)

img=cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)

#将图像进行二值化处理,小于10的为0,大于的255

ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY), 10, 255, cv2.THRESH_BINARY)

#找出图片的轮廓

image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

#绘制轮廓

cv2.drawContours(img, contours, -1, (255, 0, 0), 3)

#显示带轮廓的图片

cv2.imshow("contours", img)

#等待按键退出

cv2.waitKey()

cv2.destroyAllWindows()

结果:

 

下节课讲什么还没决定好,到时候再说哦!

———————————————

如果对我的课程感兴趣的话,欢迎关注小木希望学园-微信公众号: 

mutianwei521

也可以扫描二维码哦!


猜你喜欢

转载自blog.csdn.net/u013631121/article/details/80504032