OpenCV-Python教程(4、形态学处理)
来源:互联网 发布:程序员的英文 编辑:程序博客网 时间:2024/06/04 20:00
提示:
- 转载请详细注明原作者及出处,谢谢!
- 本文介绍使用OpenCV-Python进行形态学处理
- 本文不介绍形态学处理的基本概念,所以读者需要预先对其有一定的了解。
定义结构元素
形态学处理的核心就是定义结构元素,在OpenCV-Python中,可以使用其自带的getStructuringElement函数,也可以直接使用NumPy的ndarray来定义一个结构元素。首先来看用getStructuringElement函数定义一个结构元素:
- element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
也可以用NumPy来定义结构元素,如下:
- NpKernel = np.uint8(np.zeros((5,5)))
- for i in range(5):
- NpKernel[2, i] = 1 #感谢chenpingjun1990的提醒,现在是正确的
- NpKernel[i, 2] = 1
- [[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]]
这里可以看出,用OpenCV-Python内置的常量定义椭圆(MORPH_ELLIPSE)和十字形结构(MORPH_CROSS)元素要简单一些,如果定义矩形(MORPH_RECT)和自定义结构元素,则两者差不多。
本篇文章将用参考资料1中的相关章节的图片做测试:
腐蚀和膨胀
下面先以腐蚀图像为例子介绍如何使用结构元素:
- #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()
如上所示,腐蚀和膨胀的处理很简单,只需设置好结构元素,然后分别调用cv2.erode(...)和cv2.dilate(...)函数即可,其中第一个参数是需要处理的图像,第二个是结构元素。返回处理好的图像。
结果如下:
开运算和闭运算
了解形态学基本处理的同学都知道,开运算和闭运算就是将腐蚀和膨胀按照一定的次序进行处理。但这两者并不是可逆的,即先开后闭并不能得到原先的图像。代码示例如下:
- #coding=utf-8
- import cv2
- import numpy as np
- img = cv2.imread('D:/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.waitKey(0)
- cv2.destroyAllWindows()
闭运算用来连接被误分为许多小块的对象,而开运算用于移除由图像噪音形成的斑点。因此,某些情况下可以连续运用这两种运算。如对一副二值图连续使用闭运算和开运算,将获得图像中的主要对象。同样,如果想消除图像中的噪声(即图像中的“小点”),也可以对图像先用开运算后用闭运算,不过这样也会消除一些破碎的对象。
对原始图像进行开运算和闭运算的结果如下:
用形态学运算检测边和角点
这里通过一个较复杂的例子介绍如何用形态学算子检测图像中的边缘和拐角(这里只是作为介绍形态学处理例子,实际使用时请用Canny或Harris等算法)。
检测边缘
形态学检测边缘的原理很简单,在膨胀时,图像中的物体会想周围“扩张”;腐蚀时,图像中的物体会“收缩”。比较这两幅图像,由于其变化的区域只发生在边缘。所以这时将两幅图像相减,得到的就是图像中物体的边缘。这里用的依然是参考资料1中相关章节的图片:
代码如下:
- #coding=utf-8
- import cv2
- import numpy
- image = cv2.imread("D:/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("result",result);
- cv2.waitKey(0)
- cv2.destroyAllWindows()
检测拐角
与边缘检测不同,拐角的检测的过程稍稍有些复杂。但原理相同,所不同的是先用十字形的结构元素膨胀像素,这种情况下只会在边缘处“扩张”,角点不发生变化。接着用菱形的结构元素腐蚀原图像,导致只有在拐角处才会“收缩”,而直线边缘都未发生变化。
第二步是用X形膨胀原图像,角点膨胀的比边要多。这样第二次用方块腐蚀时,角点恢复原状,而边要腐蚀的更多。所以当两幅图像相减时,只保留了拐角处。示意图如下(示意图来自参考资料1):
代码如下:
- #coding=utf-8
- import cv2
- image = cv2.imread("D:/building.jpg", 0)
- origin = cv2.imread("D:/building.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()
大家可以验证一下,比如在代码中插入这两行代码,就能知道结果了:
- cv2.circle(image, (5, 10), 5, (255,0,0))
- image[5, 10] = 0
当然,这只是个形态学处理示例,检测结果并不好。
未完待续...
在将来的某一篇文章中将做个总结,介绍下OpenCV中常用的函数,如threshold、bitwise_xxx,以及绘制函数等。
参考资料:
1、《Opencv2 Computer Vision Application Programming Cookbook》
2、《OpenCV References Manule》
如果觉得本文写的还可以的话,请轻点“顶”,方便读者、以及您的支持是我写下去的最大的两个动力。
- OpenCV-Python教程(4、形态学处理)
- OpenCV-Python教程(4、形态学处理)
- OpenCV-Python教程(4、形态学处理)
- OpenCV-Python教程(4、形态学处理)
- OpenCV-Python教程(4、形态学处理)
- OpenCV-Python教程:形态学处理
- OpenCV Python教程(3)(4)(5): 直方图的计算与显示 形态学处理 初级滤波内
- Python OpenCV 形态学 (六)
- OpenCV入门(八)--形态学图像处理
- 【OpenCV】图像处理(二)图像形态学
- opencv学习(8)形态学图像处理
- OPENCV之形态学处理
- opencv形态学处理
- openCV 形态学图像处理
- opencv-形态学处理
- openCV 形态学处理
- opencv图像形态学处理
- OpenCV-形态学处理-morphologyEx
- OpenCV Python教程(3、直方图的计算与显示)
- Android学习 怎么将ListView默认滚动设置到后面
- 使用Xerces DOM 处理XML文件
- qimage 与cv::mat 转化--> QPixmap
- [Postgresql] 简单命令使用总结
- OpenCV-Python教程(4、形态学处理)
- mybatis的批量新增
- DB2中 between and 的边界
- iOS开发UI篇—程序启动原理和UIApplication
- 你能达到这个要求吗
- OpenCV-Python教程(5、初级滤波内容)
- Java静态方法为什么不能访问非静态方法
- Android apk的安装、卸载
- windFramework_拦截链