OpenCV-Python教程:形态学处理

2024-06-11 04:08

本文主要是介绍OpenCV-Python教程:形态学处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 转自: http://blog.csdn.net/sunny2038/article/details/9137759
  • 本文介绍使用OpenCV-Python进行形态学处理
  • 本文不介绍形态学处理的基本概念,所以读者需要预先对其有一定的了解。

定义结构元素

形态学处理的核心就是定义结构元素,在OpenCV-Python中,可以使用其自带的getStructuringElement函数,也可以直接使用NumPy的ndarray来定义一个结构元素。首先来看用getStructuringElement函数定义一个结构元素:

[python]  view plain copy
  1. element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))  
这就定义了一个5×5的十字形结构元素,如下:

也可以用NumPy来定义结构元素,如下:

[python]  view plain copy
  1. NpKernel = np.uint8(np.zeros((5,5)))  
  2. for i in range(5):  
  3.     NpKernel[2, i] = 1 #感谢chenpingjun1990的提醒,现在是正确的  
  4.     NpKernel[i, 2] = 1  
这两者方式定义的结构元素完全一样:
[python]  view plain copy
  1. [[0 0 1 0 0]  
  2.  [0 0 1 0 0]  
  3.  [1 1 1 1 1]  
  4.  [0 0 1 0 0]  
  5.  [0 0 1 0 0]]  

这里可以看出,用OpenCV-Python内置的常量定义椭圆(MORPH_ELLIPSE)和十字形结构(MORPH_CROSS)元素要简单一些,如果定义矩形(MORPH_RECT)和自定义结构元素,则两者差不多。

本篇文章将用参考资料1中的相关章节的图片做测试:


腐蚀和膨胀

下面先以腐蚀图像为例子介绍如何使用结构元素:

[python]  view plain copy
  1. #coding=utf-8  
  2. import cv2  
  3. import numpy as np  
  4.    
  5. img = cv2.imread('D:/binary.bmp',0)  
  6. #OpenCV定义的结构元素  
  7. kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(33))  
  8.   
  9. #腐蚀图像  
  10. eroded = cv2.erode(img,kernel)  
  11. #显示腐蚀后的图像  
  12. cv2.imshow("Eroded Image",eroded);  
  13.   
  14. #膨胀图像  
  15. dilated = cv2.dilate(img,kernel)  
  16. #显示膨胀后的图像  
  17. cv2.imshow("Dilated Image",dilated);  
  18. #原图像  
  19. cv2.imshow("Origin", img)  
  20.   
  21. #NumPy定义的结构元素  
  22. NpKernel = np.uint8(np.ones((3,3)))  
  23. Nperoded = cv2.erode(img,NpKernel)  
  24. #显示腐蚀后的图像  
  25. cv2.imshow("Eroded by NumPy kernel",Nperoded);  
  26.   
  27. cv2.waitKey(0)  
  28. cv2.destroyAllWindows()  

如上所示,腐蚀和膨胀的处理很简单,只需设置好结构元素,然后分别调用cv2.erode(...)和cv2.dilate(...)函数即可,其中第一个参数是需要处理的图像,第二个是结构元素。返回处理好的图像。

结果如下:


开运算和闭运算

了解形态学基本处理的同学都知道,开运算和闭运算就是将腐蚀和膨胀按照一定的次序进行处理。但这两者并不是可逆的,即先开后闭并不能得到原先的图像。代码示例如下:

[python]  view plain copy
  1. #coding=utf-8  
  2. import cv2  
  3. import numpy as np  
  4.    
  5. img = cv2.imread('D:/binary.bmp',0)  
  6. #定义结构元素  
  7. kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(55))  
  8.   
  9. #闭运算  
  10. closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)  
  11. #显示腐蚀后的图像  
  12. cv2.imshow("Close",closed);  
  13.   
  14. #开运算  
  15. opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)  
  16. #显示腐蚀后的图像  
  17. cv2.imshow("Open", opened);  
  18.   
  19. cv2.waitKey(0)  
  20. cv2.destroyAllWindows()  

闭运算用来连接被误分为许多小块的对象,而开运算用于移除由图像噪音形成的斑点。因此,某些情况下可以连续运用这两种运算。如对一副二值图连续使用闭运算和开运算,将获得图像中的主要对象。同样,如果想消除图像中的噪声(即图像中的“小点”),也可以对图像先用开运算后用闭运算,不过这样也会消除一些破碎的对象。

对原始图像进行开运算和闭运算的结果如下:


用形态学运算检测边和角点

这里通过一个较复杂的例子介绍如何用形态学算子检测图像中的边缘和拐角(这里只是作为介绍形态学处理例子,实际使用时请用Canny或Harris等算法)。

检测边缘

形态学检测边缘的原理很简单,在膨胀时,图像中的物体会想周围“扩张”;腐蚀时,图像中的物体会“收缩”。比较这两幅图像,由于其变化的区域只发生在边缘。所以这时将两幅图像相减,得到的就是图像中物体的边缘。这里用的依然是参考资料1中相关章节的图片:

代码如下:

[python]  view plain copy
  1. #coding=utf-8  
  2. import cv2  
  3. import numpy  
  4.   
  5. image = cv2.imread("D:/building.jpg",0);  
  6. #构造一个3×3的结构元素   
  7. element = cv2.getStructuringElement(cv2.MORPH_RECT,(33))  
  8. dilate = cv2.dilate(image, element)  
  9. erode = cv2.erode(image, element)  
  10.   
  11. #将两幅图像相减获得边,第一个参数是膨胀后的图像,第二个参数是腐蚀后的图像  
  12. result = cv2.absdiff(dilate,erode);  
  13.   
  14. #上面得到的结果是灰度图,将其二值化以便更清楚的观察结果  
  15. retval, result = cv2.threshold(result, 40255, cv2.THRESH_BINARY);   
  16. #反色,即对二值图每个像素取反  
  17. result = cv2.bitwise_not(result);   
  18. #显示图像  
  19. cv2.imshow("result",result);   
  20. cv2.waitKey(0)  
  21. cv2.destroyAllWindows()  
处理结果如下:

检测拐角

与边缘检测不同,拐角的检测的过程稍稍有些复杂。但原理相同,所不同的是先用十字形的结构元素膨胀像素,这种情况下只会在边缘处“扩张”,角点不发生变化。接着用菱形的结构元素腐蚀原图像,导致只有在拐角处才会“收缩”,而直线边缘都未发生变化。

第二步是用X形膨胀原图像,角点膨胀的比边要多。这样第二次用方块腐蚀时,角点恢复原状,而边要腐蚀的更多。所以当两幅图像相减时,只保留了拐角处。示意图如下(示意图来自参考资料1):

代码如下:

[python]  view plain copy
  1. #coding=utf-8  
  2. import cv2  
  3.   
  4. image = cv2.imread("D:/building.jpg"0)  
  5. origin = cv2.imread("D:/building.jpg")  
  6. #构造5×5的结构元素,分别为十字形、菱形、方形和X型  
  7. cross = cv2.getStructuringElement(cv2.MORPH_CROSS,(55))  
  8. #菱形结构元素的定义稍麻烦一些  
  9. diamond = cv2.getStructuringElement(cv2.MORPH_RECT,(55))  
  10. diamond[00] = 0  
  11. diamond[01] = 0  
  12. diamond[10] = 0  
  13. diamond[44] = 0  
  14. diamond[43] = 0  
  15. diamond[34] = 0  
  16. diamond[40] = 0  
  17. diamond[41] = 0  
  18. diamond[30] = 0  
  19. diamond[03] = 0  
  20. diamond[04] = 0  
  21. diamond[14] = 0  
  22. square = cv2.getStructuringElement(cv2.MORPH_RECT,(55))  
  23. x = cv2.getStructuringElement(cv2.MORPH_CROSS,(55))  
  24. #使用cross膨胀图像  
  25. result1 = cv2.dilate(image,cross)  
  26. #使用菱形腐蚀图像  
  27. result1 = cv2.erode(result1, diamond)  
  28.   
  29. #使用X膨胀原图像   
  30. result2 = cv2.dilate(image, x)  
  31. #使用方形腐蚀图像   
  32. result2 = cv2.erode(result2,square)  
  33.   
  34. #result = result1.copy()  
  35. #将两幅闭运算的图像相减获得角   
  36. result = cv2.absdiff(result2, result1)  
  37. #使用阈值获得二值图  
  38. retval, result = cv2.threshold(result, 40255, cv2.THRESH_BINARY)  
  39.   
  40. #在原图上用半径为5的圆圈将点标出。  
  41. for j in range(result.size):  
  42.     y = j / result.shape[0]   
  43.     x = j % result.shape[0]   
  44.   
  45.     if result[x, y] == 255:  
  46.         cv2.circle(image, (y, x), 5, (255,0,0))  
  47.   
  48. cv2.imshow("Result", image)  
  49. cv2.waitKey(0)  
  50. cv2.destroyAllWindows()  
注意,由于封装的缘故,OpenCV中函数参数中使用的坐标系和NumPy的ndarray的坐标系是不同的,在46行可以看出来。 抽空我向OpenCV邮件列表提一下,看我的理解是不是正确的。

大家可以验证一下,比如在代码中插入这两行代码,就能知道结果了:

[python]  view plain copy
  1. cv2.circle(image, (510), 5, (255,0,0))  
  2. image[510] = 0  
通过上面的代码就能检测到图像中的拐角并标出来,效果图如下:



当然,这只是个形态学处理示例,检测结果并不好。

未完待续...

在将来的某一篇文章中将做个总结,介绍下OpenCV中常用的函数,如threshold、bitwise_xxx,以及绘制函数等。

参考资料:

1、《Opencv2 Computer Vision Application Programming Cookbook》

2、《OpenCV References Manule》

如果觉得本文写的还可以的话,请轻点“顶”,方便读者、以及您的支持是我写下去的最大的两个动力。

这篇关于OpenCV-Python教程:形态学处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1050149

相关文章

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python正则表达式匹配和替换的操作指南

《Python正则表达式匹配和替换的操作指南》正则表达式是处理文本的强大工具,Python通过re模块提供了完整的正则表达式功能,本文将通过代码示例详细介绍Python中的正则匹配和替换操作,需要的朋... 目录基础语法导入re模块基本元字符常用匹配方法1. re.match() - 从字符串开头匹配2.

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下