4.5 形态学处理
写在前面:
当然,也需要格外了解些 关于数学形态学
1.形态学---图像处理基本算法
形态学一般是使用二值图像,进行边界提取,骨架提取,孔洞填充,角点提取,图像重建。基本的算法:膨胀腐蚀,开操作,闭操作,击中击不中变换。(参考:学习参考link)
2.定义元素
形态学的处理核心之一在于定义结构元素,元素选取的不同对处理后的结果会有影响。在Opencv提供了一个函数getStructuringElement,可以获取常用的结构元素的形状:矩形(包括线形)、椭圆(包括圆形)及十字形。定义一个十字行元素:
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
得到:
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
可以看到是十字行'1'
2.膨胀和腐蚀:处理的图像为二值化的图像。选取的图像为原创作者的图像:
代码(相关图像膨胀和腐蚀数学知识可以通过提供的链接进行理解,实际使用只需调用使用):
#coding=utf-8
import cv2
import numpy as np
img = cv2.imread('D:/binary.bmp',0)
#OpenCV定义的结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
#腐蚀图像
eroded = cv2.erode(img,kernel)
#显示腐蚀后的图像
cv2.imshow("Eroded Image",eroded);
#膨胀图像
dilated = cv2.dilate(img,kernel)
#显示膨胀后的图像
cv2.imshow("Dilated Image",dilated);
#原图像
cv2.imshow("Origin", img)
#NumPy定义的结构元素
NpKernel = np.uint8(np.ones((3,3)))
Nperoded = cv2.erode(img,NpKernel)
#显示腐蚀后的图像
cv2.imshow("Eroded by NumPy kernel",Nperoded);
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:3.开运算和闭运算
先腐蚀后膨胀的过程称为开运算。用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。先膨胀后腐蚀的过程称为闭运算。用来填充物体内细小空洞、连接邻近物体、平滑其边界的同时并不明显改变其面积。(具体数学方面,参考具体的那篇)
#coding=utf-8
import cv2
import numpy as np
img = cv2.imread('G:/python project/binary.bmp',0)
#定义结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))
#闭运算
closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
#显示腐蚀后的图像
cv2.imshow("Close",closed);
#开运算
opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
#显示腐蚀后的图像
cv2.imshow("Open", opened);
cv2.imshow("origin",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.检测边缘
形态学检测边缘的原理很简单,在膨胀时,图像中的物体会想周围“扩张”;腐蚀时,图像中的物体会“收缩”。比较这两幅图像,由于其变化的区域只发生在边缘。所以这时将两幅图像相减,得到的就是图像中物体的边缘。
参考图片:
代码:
#coding=utf-8
import cv2
import numpy
image = cv2.imread("G:/python project/building.jpg",0);
#构造一个3×3的结构元素
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dilate = cv2.dilate(image, element)
erode = cv2.erode(image, element)
#将两幅图像相减获得边,第一个参数是膨胀后的图像,第二个参数是腐蚀后的图像
result = cv2.absdiff(dilate,erode);
#上面得到的结果是灰度图,将其二值化以便更清楚的观察结果
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY);
#反色,即对二值图每个像素取反
result = cv2.bitwise_not(result);
#显示图像
cv2.imshow("origin",image)
cv2.imshow("result",result);
cv2.waitKey(0)
cv2.destroyAllWindows()
处理结果:
5.检测拐角
与边缘检测不同,拐角的检测的过程稍稍有些复杂。但原理相同,所不同的是先用十字形的结构元素膨胀像素,这种情况下只会在边缘处“扩张”,角点不发生变化。接着用菱形的结构元素腐蚀原图像,导致只有在拐角处才会“收缩”,而直线边缘都未发生变化。 第二步是用X形膨胀原图像,角点膨胀的比边要多。这样第二次用方块腐蚀时,角点恢复原状,而边要腐蚀的更多。所以当两幅图像相减时,只保留了拐角处。
代码:
#coding=utf-8
import cv2
image = cv2.imread("G:/python project/skirt.jpg", 0)
origin = cv2.imread("G:/python project/skirt.jpg")
#构造5×5的结构元素,分别为十字形、菱形、方形和X型
cross = cv2.getStructuringElement(cv2.MORPH_CROSS,(5, 5))
#菱形结构元素的定义稍麻烦一些
diamond = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))
diamond[0, 0] = 0
diamond[0, 1] = 0
diamond[1, 0] = 0
diamond[4, 4] = 0
diamond[4, 3] = 0
diamond[3, 4] = 0
diamond[4, 0] = 0
diamond[4, 1] = 0
diamond[3, 0] = 0
diamond[0, 3] = 0
diamond[0, 4] = 0
diamond[1, 4] = 0
square = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))
x = cv2.getStructuringElement(cv2.MORPH_CROSS,(5, 5))
#使用cross膨胀图像
result1 = cv2.dilate(image,cross)
#使用菱形腐蚀图像
result1 = cv2.erode(result1, diamond)
#使用X膨胀原图像
result2 = cv2.dilate(image, x)
#使用方形腐蚀图像
result2 = cv2.erode(result2,square)
#result = result1.copy()
#将两幅闭运算的图像相减获得角
result = cv2.absdiff(result2, result1)
#使用阈值获得二值图
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY)
#在原图上用半径为5的圆圈将点标出。
for j in range(result.size):
y = j / result.shape[0]
x = j % result.shape[0]
if result[x, y] == 255:
cv2.circle(image, (y, x), 5, (255,0,0))
cv2.imshow("Result", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
处理后的结果:
原创自:http://blog.csdn.net/sunny2038/article/details/9137759(作者:sunny2038)