提示:

转载请详细注明原作者及出处,谢谢!

本文介绍使用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、形态学处理)的更多相关文章

  1. OpenCV Python教程(3、直方图的计算与显示)

    转载请详细注明原作者及出处,谢谢! 本篇文章介绍如何用OpenCV Python来计算直方图,并简略介绍用NumPy和Matplotlib计算和绘制直方图 直方图的背景知识.用途什么的就直接略过去了. ...

  2. OpenCV Python教程(1、图像的载入、显示和保存)

    原文地址:http://blog.csdn.net/sunny2038/article/details/9057415 转载请详细注明原作者及出处,谢谢! 本文是OpenCV  2 Computer ...

  3. 【OpenCV新手教程之十一】 形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/23184547 作者:毛星云(浅墨) ...

  4. 系列文章 -- OpenCV入门教程

     <OpenCV3编程入门>内容简介&勘误&配套源代码下载 [OpenCV入门教程之十八]OpenCV仿射变换 & SURF特征点描述合辑 [OpenCV入门教程之 ...

  5. Ubuntu系统---安装Caffe (+OpenCV+Python+CPU-only)

    安装配置Ubuntu14.04+Caffe (+OpenCV+Python+CPU-only) 记录 [作者:Wu Ping.时间:20180428.] 本人已经安装很多次的Caffe了:从开始的初探 ...

  6. OpenCV/Python/dlib眨眼检测

    今天我们来使用面部标志和OpenCV 检测和计算视频流中的眨眼次数. 为了构建我们的眨眼检测器,我们将计算一个称为眼睛纵横比(EAR)的指标,由Soukupová和Čech在其2016年的论文&quo ...

  7. 《简明python教程》笔记一

    读<简明Python教程>笔记: 本书的官方网站是www.byteofpython.info  安装就不说了,网上很多,这里就记录下我在安装时的问题,首先到python官网下载,选好安装路 ...

  8. 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0 +VS 2013 开发环境配置

    图片太多,具体过程参照: [OpenCV入门教程之一] 安装OpenCV:OpenCV 3.0.OpenCV 2.4.8.OpenCV 2.4.9 +VS 开发环境配置 说下我这边的设置: 选择deb ...

  9. 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析(转)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/20537737 作者:毛星云(浅墨)  ...

  10. 学习opencv中文版教程——第二章

    学习opencv中文版教程——第二章 所有案例,跑起来~~~然而并没有都跑起来...我只把我能跑的都尽量跑了,毕竟看书还是很生硬,能运行能出结果,才比较好. 越着急,心越慌,越是着急,越要慢,越是陌生 ...

随机推荐

  1. javascript笔记整理(对象基础)

    一.名词解释 1.基于对象(一切皆对象,以对象的概念来编程) 2.面向对象编程(Object Oriented Programming,OOP) A.对象(JavaScript 中的所有事物都是对象) ...

  2. TTimerThread和TThreadedTimer(都是通过WaitForSingleObject和CreateEvent来实现的)

    //////////////////////////////////////////////////// // // // ThreadedTimer 1.24 // // // // Copyrig ...

  3. 写程序取自己进程的AEP

    测试程序功能 打印出自己进程的程序入口点地址. 结合OD载入程序,看到的入口点确实是0x004014f0, 说明程序入口点找到了 测试程序 /// @file exam_1_1.c #include  ...

  4. cocos2d-x游戏开发系列教程-坦克大战游戏关卡选择场景的编写下

    上篇文章写了Paddle类来处理精灵的点击.触摸事件,现在我们在Paddle的基础上 写一个MyPaddle类,来处理上一关.下一关.开始游戏按钮的点击事件. 1.类声明如下: class MyPad ...

  5. 基于visual Studio2013解决C语言竞赛题之1091多项式

        题目 解决代码及点评 /************************************************************************/ /* ...

  6. 一起talk GDB吧(第六回:GDB改动程序执行环境)

    各位看官们,大家好,上一回中我们说的是GDB查看信息的功能,而且说了怎样使用GDB查看程序执行时的 信息.这一回中,我们继续介绍GDB的调试功能:改动程序执行环境.当然了,我们也会介绍怎样使用GDB ...

  7. Swift - 实现点击UITableView单元格时自动展开单元格

    下面是一个列表单元格cell的折叠展开效果的demo.当点击单元格时会展开该单元格,便于显示一些详情什么的.点击其他单元格原来的会关闭,同时有动画效果. 效果如如下:   代码如下: 1 2 3 4 ...

  8. 一步一步实现FormsAuthentic验证登录

    本文不讲原理,只讲用法,原理性的东西网上特别多,不过还是会对一些要用到的东西进行解释,不深入讲原理.本文中用的是Vs2012   .net mvc 4.0.原理看这篇文章,看完这个文章绝对受益匪浅. ...

  9. VS2008下编译BOOST 1.39的ASIO库

    由于全部编译BOOST库需要的时间太长,而且耗费空间,况且我只需要用ASIO库,所以就没有必要全部编译了. boost库到www.boost.org上下载. 编译很简单,假设你的boost存放的目录是 ...

  10. .htaccess和license文件编写

    1 .htaccess 1.1 文件的位置 默认情况下放置于根目录 1.2 .htaccess文件的编写 1.2.1 错误页面跳转 ErrorDocument + 错误码 + 跳转路径/提示文字 eg ...