python 简单图形_python 简单图像处理(16) 图像的细化(骨架抽取)

图像的细化主要是针对二值图而言

所谓骨架,可以理解为图像的中轴,,一个长方形的骨架,是它的长方向上的中轴线,

圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。

骨架的获取主要有两种方法:

(1)基于烈火模拟

设想在同一时刻,将目标的边缘线都点燃,火的前沿以匀速向内部蔓延,当前沿相交时火焰熄灭,

火焰熄灭点的结合就是骨架。

(2)基于最大圆盘

目标的骨架是由目标内所有内切圆盘的圆心组成

2011010114473495.png

我们来看看典型的图形的骨架(用粗线表示)

细化的算法有很多种,但比较常用的算法是查表法

细化是从原来的图中去掉一些点,但仍要保持原来的形状。

实际上是保持原图的骨架。

判断一个点是否能去掉是以8个相邻点(八连通)的情况来作为判据的,具体判据为:

1,内部点不能删除

2,鼓励点不能删除

3,直线端点不能删除

4,如果P是边界点,去掉P后,如果连通分量不增加,则P可删除

2011010114592790.png

看看上面那些点。

第一个点不能去除,因为它是内部点

第二个点不能去除,它也是内部点

第三个点不能去除,删除后会使原来相连的部分断开

第四个点可以去除,这个点不是骨架

第五个点不可以去除,它是直线的端点

第六个点不可以去除,它是直线的端点

对于所有的这样的点,我们可以做出一张表,来判断这样的点能不能删除

2011010115150625.png

我们对于黑色的像素点,对于它周围的8个点,我们赋予不同的价值,

若周围某黑色,我们认为其价值为0,为白色则取九宫格中对应的价值

对于前面那幅图中第一个点,也就是内部点,它周围的点都是黑色,所以他的总价值是0,对应于索引表的第一项

前面那幅图中第二点,它周围有三个白色点,它的总价值为1+4+32=37,对应于索引表中第三十八项

我们用这种方法,把所有点的情况映射到0~255的索引表中

我们扫描原图,对于黑色的像素点,根据周围八点的情况计算它的价值,然后查看索引表中对应项来决定是否要保留这一点

我们很容易写出程序

importcvdefThin(image,array):

h=image.height

w=image.width

iThin=cv.CreateImage(cv.GetSize(image),8,1)

cv.Copy(image,iThin)foriinrange(h):forjinrange(w):ifimage[i,j]==0:

a=[1]*9forkinrange(3):forlinrange(3):if-1<(i-1+k)

a[k*3+l]=0

sum=a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128iThin[i,j]=array[sum]*255returniThindefTwo(image):

w=image.width

h=image.height

size=(w,h)

iTwo=cv.CreateImage(size,8,1)foriinrange(h):forjinrange(w):

iTwo[i,j]=0ifimage[i,j]<200else255returniTwo

array=[0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\

0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\

0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\

0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]

image=cv.LoadImage('pic3.jpg',0)

iTwo=Two(image)

iThin=Thin(iTwo,array)

cv.ShowImage('image',image)

cv.ShowImage('iTwo',iTwo)

cv.ShowImage('iThin',iThin)

cv.WaitKey(0)

我们来看看运行效果:

2011010115352428.png

2011010115362637.png

(下图最左边的原图若涉及版权问题,请作者与我联系,谢谢)

效果差强人意,总觉得有点不对头,但又说不出哪里不对

好吧,我们来看看最简单的事例

2011010115394223.png

按照前面的分析,我们应该得到一条竖着的线,但实际上我们得到了一条横线

我们在从上到下,从左到右扫描的时候,遇到第一个点,我们查表可以删除,遇到第二个点,我们查表也可以删除,整个第一行都可以删除

于是我们查看第二行时,和第一行一样,它也被整个删除了。这样一直到最后一行,于是我们得到最后的结果是一行直线

解决的办法是:

在每行水平扫描的过程中,先判断每一点的左右邻居,如果都是黑点,则该点不做处理。另外,如果某个黑店被删除了,则跳过它的右邻居,处理下一点。对矩形这样做完一遍,水平方向会减少两像素。

然后我们再改垂直方向扫描,方法一样。

这样做一次水平扫描和垂直扫描,原图会“瘦”一圈

多次重复上面的步骤,知道图形不在变化为止

这一改进让算法的复杂度的运行时间增大一个数量级

我们来看看改进后的算法:

importcvdefVThin(image,array):

h=image.height

w=image.width

NEXT=1foriinrange(h):forjinrange(w):ifNEXT==0:

NEXT=1else:

M=image[i,j-1]+image[i,j]+image[i,j+1]if0

a=[0]*9forkinrange(3):forlinrange(3):if-1<(i-1+k)

a[k*3+l]=1sum=a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128image[i,j]=array[sum]*255ifarray[sum]==1:

NEXT=0returnimagedefHThin(image,array):

h=image.height

w=image.width

NEXT=1forjinrange(w):foriinrange(h):ifNEXT==0:

NEXT=1else:

M=image[i-1,j]+image[i,j]+image[i+1,j]if0

a=[0]*9forkinrange(3):forlinrange(3):if-1<(i-1+k)

a[k*3+l]=1sum=a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128image[i,j]=array[sum]*255ifarray[sum]==1:

NEXT=0returnimagedefXihua(image,array,num=10):

iXihua=cv.CreateImage(cv.GetSize(image),8,1)

cv.Copy(image,iXihua)foriinrange(num):

VThin(iXihua,array)

HThin(iXihua,array)returniXihuadefTwo(image):

w=image.width

h=image.height

size=(w,h)

iTwo=cv.CreateImage(size,8,1)foriinrange(h):forjinrange(w):

iTwo[i,j]=0ifimage[i,j]<200else255returniTwo

array=[0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\

0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\

0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\

0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]

image=cv.LoadImage('pic3.jpg',0)

iTwo=Two(image)

iThin=Xihua(iTwo,array)

cv.ShowImage('image',image)

cv.ShowImage('iTwo',iTwo)

cv.ShowImage('iThin',iThin)

cv.WaitKey(0)

我们在调用函数的时候可以控制扫描的次数,而不是判断是否扫描完成

好啦,我们来看看运行效果吧。

2011010116065743.png

2011010116075762.png

效果确实比刚才好多了

我们来看看对复杂图形的效果

2011010116220191.png

2011010116234613.png

(上图中左图若有版权问题,请与我联系,谢谢)

好啦,图像的细化就讲到这里了

之后一段时间要准备考研,虽然并不认为自己还来得及复习,但总得做出点姿态

呵呵,可能之后两个星期不再更新

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值