OpenCV-Python教程(4、形态学处理)
提示:
转载请详细注明原作者及出处,谢谢!
本文介绍使用OpenCV-Python进行形态学处理
本文不介绍形态学处理的基本概念,所以读者需要预先对其有一定的了解。
定义结构元素
形态学处理的核心就是定义结构元素,在OpenCV-Python中,可以使用其自带的getStructuringElement函数,也可以直接使用NumPy的ndarray来定义一个结构元素。首先来看用getStructuringElement函数定义一个结构元素:
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
这就定义了一个5×5的十字形结构元素,如下:
也可以用NumPy来定义结构元素,如下:
NpKernel = np.uint8(np.zeros((5,5)))
for i in range(5):
NpKernel[1, i] = 1
NpKernel[i, 1] = 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()
注意,由于封装的缘故,OpenCV中函数参数中使用的坐标系和NumPy的ndarray的坐标系是不同的,在50行可以看出来。抽空我向OpenCV邮件列表提一下,看我的理解是不是正确的。
大家可以验证一下,比如在代码中插入这两行代码,就能知道结果了:
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教程(3、直方图的计算与显示)
转载请详细注明原作者及出处,谢谢! 本篇文章介绍如何用OpenCV Python来计算直方图,并简略介绍用NumPy和Matplotlib计算和绘制直方图 直方图的背景知识.用途什么的就直接略过去了. ...
- OpenCV Python教程(1、图像的载入、显示和保存)
原文地址:http://blog.csdn.net/sunny2038/article/details/9057415 转载请详细注明原作者及出处,谢谢! 本文是OpenCV 2 Computer ...
- 【OpenCV新手教程之十一】 形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽合辑
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/23184547 作者:毛星云(浅墨) ...
- 系列文章 -- OpenCV入门教程
<OpenCV3编程入门>内容简介&勘误&配套源代码下载 [OpenCV入门教程之十八]OpenCV仿射变换 & SURF特征点描述合辑 [OpenCV入门教程之 ...
- Ubuntu系统---安装Caffe (+OpenCV+Python+CPU-only)
安装配置Ubuntu14.04+Caffe (+OpenCV+Python+CPU-only) 记录 [作者:Wu Ping.时间:20180428.] 本人已经安装很多次的Caffe了:从开始的初探 ...
- OpenCV/Python/dlib眨眼检测
今天我们来使用面部标志和OpenCV 检测和计算视频流中的眨眼次数. 为了构建我们的眨眼检测器,我们将计算一个称为眼睛纵横比(EAR)的指标,由Soukupová和Čech在其2016年的论文&quo ...
- 《简明python教程》笔记一
读<简明Python教程>笔记: 本书的官方网站是www.byteofpython.info 安装就不说了,网上很多,这里就记录下我在安装时的问题,首先到python官网下载,选好安装路 ...
- 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0 +VS 2013 开发环境配置
图片太多,具体过程参照: [OpenCV入门教程之一] 安装OpenCV:OpenCV 3.0.OpenCV 2.4.8.OpenCV 2.4.9 +VS 开发环境配置 说下我这边的设置: 选择deb ...
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析(转)
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/20537737 作者:毛星云(浅墨) ...
- 学习opencv中文版教程——第二章
学习opencv中文版教程——第二章 所有案例,跑起来~~~然而并没有都跑起来...我只把我能跑的都尽量跑了,毕竟看书还是很生硬,能运行能出结果,才比较好. 越着急,心越慌,越是着急,越要慢,越是陌生 ...
随机推荐
- ImageMagick 压缩图片 方法
Images as a percentage of page weight for the Alexa top 10 global web sites 图片在站点所占的比重越来越重.更好的优化图片能 ...
- Linux笔记——linux下的语音合成系统
1.festival 安装:sudo apt-get install festival 使用: (SayText "Hello!") 2. espeek(ubuntu 自带) # ...
- 利用opencv中的级联分类器进行人脸检測-opencv学习(1)
OpenCV支持的目标检測的方法是利用样本的Haar特征进行的分类器训练,得到的级联boosted分类器(Cascade Classification).注意,新版本号的C++接口除了Haar特征以外 ...
- NYOJ10,skiing
skiing 时间限制:3000 ms | 内存限制:65535 KB 难度:5 描写叙述 Michael喜欢滑雪百这并不奇怪, 由于滑雪的确非常刺激.但是为了获得速度,滑的区域必须向下倾斜,并且 ...
- PHP - 接口&抽象类
什么时候使用抽象类什么时候使用接口? .如果要创建一个模型,这个模型将由一些紧密相关的对象采用,就可以使用抽象类.如果要创建将由一些不相关对象采用的功能,就使用接口. .如果必须从多个来源继承行为,就 ...
- Session 转台服务器的使用方法
Session的缺陷:为了保持自身的稳定,IIS在访问量大的时候,可能会不自觉的重启,这时候Session就会丢失用户就会被迫下线 解决方案1:将Session放到一个专门的转台服务器上 方案2:将S ...
- SpringMVC 返回字符串
今天看到一段代码,关于SpringMVC的Controller中返回字符串的代码,这段代码被我称为2b代码(英文名:2b Code). @RequestMapping(value="twoB ...
- hdu5338 ZZX and Permutations
hdu5338 ZZX and Permutations 非原创,来自多校题解 不是自己写的,惭愧ing…… 留着以后自己参考…… lower_bound {1,2,4,5} 询问 2,返回的是 2 ...
- android https通过载入pfx证书获取数据
直接给代码吧.研究了几天才搞定...... public static final String CLIENT_KET_PASSWORD = "Ku6OpqKDfN4=305790" ...
- Eclipse用法和技巧九:自动添加try/catch块2
上一篇介绍了如何给未检查异常快速增加try/catch语句,这里在补充一点其他相关操作.有时候我们增加了try/catch之后还需要在加一个finally块,比如android上每次分配一个curso ...