一、图像的细化
基础概念
细化技术:把一个平面区域简化成图的结构形状表示法
骨架:一种细化的结构,它是目标重要的拓扑描述,具有很广泛的应用,再图像识别或者数据压缩时候,经常要用到细化结构。减少数据的冗余量,去掉没用用的信息
细化算法:采取逐次去除边界的方法来进行的,不能破环图像的连通性
通常我们会定义一个规则,来判断哪个点可以删除,哪个点不能删除。
在细化图像的过程中,应该满足两个条件:
- 在细化的过程中,X应该有规律地缩小
- 在X逐步缩小的过程中,应该使X的连通性质保持不变()
细化算法过程
图像在进行细化的时候,无非就是逐渐删除图像中的一些点。但是在删除点的时候,我们要明白哪些点可以删除,哪些点不能删除。
比如上述六副图像中,我们来逐一分析,中心像元能否进行删除。
1.第一幅图像不能删除,因为其中心像元是内部点
2.第二幅图像也不能删除,因为他也是内部点
3.第三幅图像也不能删除,因为删除了,直线就断掉了
4.第四幅图像可以删除
5.第五副图像不可以删除,因为他是一个直线的端点
6.第六幅图像也不能删除,因为他是一个直线的端点
进行总结一下,可以得出
- 内部点不能删除;
- 孤立点不能删除;
- 直线端点不能删除;
- 如果P是边界点,去掉P后,如果连通分量不增加,则P可以删除
所以,我们现在的算法的目标就是要判断每个点属于哪种情况,能不能进行删除,算法思想大概如下
-
创建出一个5*5的结构元素,对图像进行遍历
-
当遍历到某个元素时,如果当前像素为黑,将该5*5的结构元素的中心覆盖在欲判断的像素上,如果S模板所覆盖的位置下,像素值为白,则置0,否则置1.
-
判断其中心像元,即P12是否满足四个条件,如果满足,则删除,不满足则保留
-
循环执行,直到图像中没有可以删除的点为止。
整个算法最精妙的地方就是那四个条件,在介绍前,先说明一下
N
(
P
x
)
N(P_{x})
N(Px)表示以
P
x
x
P_{xx}
Pxx为中心的三领域中黑色点的个数,如下图,
N
(
P
12
)
N(P_{12})
N(P12)=3
T
(
P
x
)
T(P_{x})
T(Px)表示以
P
x
P_{x}
Px为中心的三领域中,白黑跳变的个数,如下图,在P7-P8-P13-18-P17-P17-P16-P11-P6-P7这个从白色突变到黑色的个数就是
T
(
P
x
)
T(P_x)
T(Px)的取值,
T
(
P
12
)
T(P_{12})
T(P12)=2
- 2<=N(P12)<=12
- T(P12)=1
- P7 * P11* P13=0 或者T(P7)!=1
- P7 * P11 * P17=0 或则T(P11)!=1
现在说明一下,为什么满足上述四个条件的点才可以删除。
条件1,保证了中心点周围的黑色点的数量在2-6个,如果小于2个,那么这个点就是孤立点或者端点,如下图
条件2保证了,删除这个点不会影响连通性,如下面的第一张图,该图的T(P12)=2,如果删除该点,P8和P18的连通信就会受到影响。第二张图的T(P12)=1,如果删除该点,其连通信不会改变
对于条件三,我们先来讨论一下,不满足条件三的第一个子条件的情况,即P7 * P11* P13!=0,即他们都为黑色,你可能会画出这样的图像
上述图像连第二关都过不去,因为T(p12)=2,所以,要想过第二关,必须是下面这样的
当第一个子条件不通过的时候,会判断第二个子条件,即T(p7)!=1,上述的T(P7)肯定是等于1的,还剩下下面三种情况
可以看到,下面三种情况,只有图2的T(P7)!=1,所以1、3不能删,2可以删。这是为了防止迭代的时候渐进的删除。
现在假设,我们对图1进行遍历,此时遍历到p7点,因为p7是满足条件的,所以我们就把p7给删掉,变成下面的图像了
但是,这次迭代才遍历到p7!缓存图像还有没遍历完,所以当我们遍历到p12的时候,缓存图像任然是下面的,但是实际图像已经变成上面那样了
此时,我们遍历到p12,如果我们不设置条件3和条件4的话,那么这个点就满足条件1和条件2,这个点就会被删除,然后图像就变成下面那样了
很明显,发生了断线!
假设,我们加上第三个和第四个条件,就不会产生这种情况了。
那么为什么第三个和第四个条件里,还有个子条件呢?
你想想,我们在删除P12的时候,如果我们知道P12上面的点不可能会被删除,那么删除P12之后就不会发生断连。
那什么情况下P12上面的点不可能被删除呢?
即T(p7)!=1
结论,条件三是为了防止水平线发生断连,条件四是为了防止垂直线发生断连
Pyhton代码实现
def imageFragement(self):
def getCount(v_list):
v_list=v_list.flatten()
count = 0
last_flag = None
for i in [1, 2, 5, 8, 7, 6, 3, 0, 1]:
if last_flag is None:
last_flag = v_list[i]
else:
if v_list[i] == True and last_flag == False:
count = count + 1
last_flag = v_list[i]
return count
# 第一步生成一个5*5的模板
width = 5 # 首先判断结构元素的大小
v_w = int(width / 2) # 得到中心点到边界的大小
# 可以使用模板的区域进行遍历
targetImg=self.Img
while True:
imgbuf = np.copy(targetImg)
flag=False
for y in range(v_w, self.f_height - v_w):
for x in range(v_w, self.f_width - v_w):
if imgbuf[y, x, 0] == 255:
continue
v_values = imgbuf[y - v_w:y + v_w + 1, x - v_w:x + v_w + 1, 0] # 得到所有像素元的值
v = np.empty(shape=[5, 5], dtype=bool) # 新创建一个动态模板
v[:, :] = False
v[v_values == 0] = True
v1 = v[1:4, 1:4].flatten()
s = np.sum(v1[[1, 2, 5, 8, 7, 6, 3, 0]])
if s < 2 or s > 6: # condition 1
continue
if getCount(v[1:4, 1:4]) != 1: # condition 2
continue
if not (v1[1] * v1[3] * v1[5] == 0 or getCount(v[0:3, 1:4]) != 1): # condition 3
continue
if not (v1[1] * v1[3] * v1[7] == 0 or getCount(v[1:4, 0:3]) != 1): # condition 4
continue
targetImg[y, x, :] = 255
flag=True
if not flag:
break
self.Img=targetImg
原图如下
细化算法处理过后的图像如下