膨胀与腐蚀一般用于二值图,也很好理解。但是对于灰度图,显然也存在腐蚀与膨胀,这是如何进行的呢?
可以使用OpenCV中的库函数cv2.erode和cv2.dilate,但这次是探究其中的原理。
灰值形态学
结构元素(structure element)
$5 imes 5$结构元素示例:
(2)欧几里得距离(Euclidean distance)
0 | 1 | 1 | 1 | 0 |
1 | 2 | 2 | 2 | 1 |
1 | 2 | 2 | 2 | 1 |
1 | 2 | 2 | 2 | 1 |
0 | 1 | 1 | 1 | 0 |
(2)城市街区距离(city block distance)
0 | 0 | 1 | 0 | 0 |
0 | 1 | 2 | 1 | 0 |
1 | 2 | 3 | 2 | 1 |
0 | 1 | 2 | 1 | 0 |
0 | 0 | 1 | 0 | 0 |
(3)棋盘距离(Chess board distance)
1 | 1 | 1 | 1 | 1 |
1 | 2 | 2 | 2 | 1 |
1 | 2 | 3 | 2 | 1 |
1 | 2 | 2 | 2 | 1 |
1 | 1 | 1 | 1 | 1 |
腐蚀(Erosion)
灰度图像的腐蚀运算的数学定义为:
$(foplus b) = max{f(s-x,t-y) + b(x,y)|(s-x,t-y) in D_f;(x,y) in D_b }$
即加上权重后取最大值。
膨胀(Dilation)
数学定义:
$(fcircledast b) = min{f(s-x,t-y) - b(x,y)|(s-x,t-y) in D_f;(x,y) in D_b }$
即减去权重取最小值
在灰度形态学中,一般选择平坦的结构元素。所谓“平坦”,就是指结构元素的高度为零,即b的值全为0,则上面两个公式可以重写为:
$$(foplus b) = max{f(s-x,t-y)|(s-x,t-y) in D_f;(x,y) in D_b }$$
$$(fcircledast b) = min{f(s-x,t-y)|(s-x,t-y) in D_f;(x,y) in D_b }$$
代码
(写得太丑了)
def my_dilation(img, kernel): ret = img.copy() l1 = int((kernel.shape[0] - 1) / 2) l2 = int((kernel.shape[1] - 1) / 2) for i in range(l1,img.shape[0]-l1): for j in range(l2,img.shape[1]-l2): values = [] for k1 in range(-l1, l1 + 1): for k2 in range(-l2, l2 + 1): v = int(img[i+k1][j+k2]) + int(kernel[k1+l1][k2+l2]) if v > 255: v = 255 values.append(v) ret[i][j] = max(values) return ret def my_erosion(img, kernel): ret = img.copy() l1 = int((kernel.shape[0] - 1) / 2) l2 = int((kernel.shape[1] - 1) / 2) for i in range(l1,img.shape[0]-l1): for j in range(l2,img.shape[1]-l2): values = [] for k1 in range(-l1, l1 + 1): for k2 in range(-l2, l2 + 1): v = int(img[i+k1][j+k2]) - int(kernel[k1+l1][k2+l2]) if v > 255: v = 255 values.append(v) ret[i][j] = min(values) return ret
参考链接:https://blog.csdn.net/guoyk1990/article/details/8134134