OpenCV:入门(四)

形态学操作

形态学,即数学形态学(Mathematical Morphology),是图像处理过程中一个非常重要的研 究方向。形态学主要从图像内提取分量信息,该分量信息通常对于表达和描绘图像的形状具有 重要意义,通常是图像理解时所使用的最本质的形状特征。例如,在识别手写数字时,能够通 过形态学运算得到其骨架信息,在具体识别时,仅针对其骨架进行运算即可。形态学处理在视 觉检测、文字识别、医学图像处理、图像压缩编码等领域都有非常重要的应用。

形态学操作主要包含:腐蚀、膨胀、开运算、闭运算、形态学梯度(Morphological Gradient) 运算、顶帽运算(礼帽运算)、黑帽运算等操作。腐蚀操作和膨胀操作是形态学运算的基础, 将腐蚀和膨胀操作进行结合,就可以实现开运算、闭运算、形态学梯度运算、顶帽运算、黑帽 运算、击中击不中等不同形式的运算。

一,腐蚀

腐蚀是最基本的形态学操作之一,它能够将图像的边界点消除,使图像沿着边界向内收缩, 也可以将小于指定结构体元素的部分去除。

1.原理

整幅图像的背景色是黑色的,前景对象是一个白色的圆形。图像左上角的深色小方块是遍历图像所使用的结构元。在腐蚀过程中,要将该结构元逐个像素地遍历整 幅图像,并根据结构元与被腐蚀图像的关系,来确定腐蚀结果图像中对应结构元中心点位置的 像素点的值。

需要注意的是,腐蚀操作等形态学操作是逐个像素地来决定值的,每次判定的点都是与结构元中心点所对应的点。

  • 如果结构元完全处于前景图像中(图 8-3 的左图),就将结构元中心点所对应的腐蚀结 果图像中的像素点处理为前景色(白色,像素点的像素值为 1)。
  • 如果结构元未完全处于前景图像中(可能部分在,也可能完全不在,图 8-3 的右图), 就将结构元中心点对应的腐蚀结果图像中的像素点处理为背景色(黑色,像素点的像素 值为 0)。

针对图 8-3 中的图像,腐蚀的结果就是前景色的白色圆直径变小。上述结构元也被称为核。 例如,有需要被腐蚀的图像 img,其值如下,其中 1 表示白色前景,0 表示黑色背景:

核的结构为:

腐蚀其实就是原图像通过核来逐个计算每个像素,最后得到腐蚀图像。包括下文中的膨胀原理也大差不大,你可以简单地将膨胀理解为腐蚀的逆,只不过膨胀对点的处理不同而已。但是核的结构也是一致的。

2.代码示例 

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5,5),np.uint8)
img_erosion = cv2.erode(img,kernel,iterations=2)
plt.subplot(331),plt.imshow(img),plt.title("Origin")
plt.subplot(332),plt.imshow(img_erosion),plt.title("Erosion")
plt.show()
cv2.waitKey(0)

对比两幅图片,我们发现腐蚀操作明显将毛刺给过滤腐蚀掉了,但同时我们也发现了字体瘦了一圈,这是腐蚀操作不得不带来的。接下来我们讲解一下上述代码中的函数。

首先我们用imread读取目标图片,通过np.ones生成一个5x5的核,根据原理我们知道里面的值要求为1,接下来调用erode腐蚀函数对图片进行处理,参数基本只要写上述的三个(源,核,迭迭代次数)。接下来就是用matplotlib绘制出来就可以了。当然,它还有个参数borderType,可以参考了解一下:

二,膨胀

膨胀操作是形态学中另外一种基本的操作。膨胀操作和腐蚀操作的作用是相反的,膨胀操 作能对图像的边界进行扩张。膨胀操作将与当前对象(前景)接触到的背景点合并到当前对象 内,从而实现将图像的边界点向外扩张。如果图像内两个对象的距离较近,那么在膨胀的过程 中,两个对象可能会连通在一起。膨胀操作对填补图像分割后图像内所存在的空白相当有帮助。

1.原理

  • 如果结构元中任意一点处于前景图像中,就将膨胀结果图像中对应像素点处理为前景色。
  • 如果结构元完全处于背景图像外,就将膨胀结果图像中对应像素点处理为背景色。 

这就是膨胀和腐蚀之间的差别,其他的都差不多,就是对点的处理不一样。

2.代码示例

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('manolo_1.jpg')
circle = cv2.imread('circle.jpg')
kernel = np.ones((5,5),np.uint8)
img_erosion = cv2.erode(img,kernel,iterations=2)
img_dilate = cv2.dilate(img_erosion,kernel,iterations=2)
circle_dilate_1 = cv2.dilate(circle,kernel=kernel,iterations=1)
circle_dilate_2 = cv2.dilate(circle,kernel=kernel,iterations=3)
circle_dilate_3 = cv2.dilate(circle,kernel=kernel,iterations=10)

plt.subplot(331),plt.imshow(img),plt.title("Origin")
plt.subplot(332),plt.imshow(img_erosion),plt.title("Erosion")
plt.subplot(333),plt.imshow(img_dilate),plt.title("Erosion-Dilate")
plt.subplot(334),plt.imshow(circle_dilate_1),plt.title("Circle_Dilate_1")
plt.subplot(335),plt.imshow(circle_dilate_2),plt.title("Circle_Dilate_2")
plt.subplot(336),plt.imshow(circle_dilate_3),plt.title("Circle_Dilate_3")

plt.show()
cv2.waitKey(0)

我们看到第三幅图像,发现它既保留了原有的大小又除去了毛刺,这是因为我们先使用了腐蚀再使用了膨胀,这个过程我们后续称为开运算。 

三,形态学函数

腐蚀操作和膨胀操作是形态学运算的基础,将腐蚀和膨胀操作进行组合,就可以实现开运 算、闭运算(关运算)、形态学梯度(Morphological Gradient)运算、礼帽运算(顶帽运算)、 黑帽运算、击中击不中等多种不同形式的运算。

dst = cv2.morphologyEx( src, op, kernel[, anchor[, iterations[, borderType[, borderValue]]]]] )

形态学函数很好理解:它相当于把我们本章所有内容融合到了一个函数中,我们可以设置op的值来选择我们的形态学操作:比如上文的erode和dilate函数可以直接用morphologyEx()函数调用。当然,也包含我们后续的开运算,闭运算,梯度运算,礼帽运算(顶帽),黑帽运算。

接下来我们用形态学函数来讲解内容。

四,开运算

开运算进行的操作是先将图像腐蚀,再对腐蚀的结果进行膨胀。开运算可以用于去噪、计 数等。  

开运算 = erode + dilate 

1.代码示例

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5, 5), np.uint8)
img_open = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)#cv2.MORPH_OPEN 开运算:先腐蚀,再膨胀
img_close = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)#cv2.MORPH_CLOSE 闭运算,先膨胀,再腐蚀

#对比
plt.subplot(121),plt.imshow(img_open),plt.title("OPEN")
plt.subplot(122),plt.imshow(img_close),plt.title("CLOSE")
plt.show()

cv2.waitKey(0)

这里由于开运算和闭运算只是顺序不同,所以我把开运算和闭运算结果放在一起了,我们先看开运算,这个结果其实和先腐蚀后膨胀差不多,但是效果差了一点。 

五,闭运算

闭运算是先膨胀、后腐蚀的运算,它有助于关闭前景物体内部的小孔,或去除物体上的小 黑点,还可以将不同的前景图像进行连接。

闭运算 = dilate + erode 

1.代码示例

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5, 5), np.uint8)
img_open = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)#cv2.MORPH_OPEN 开运算:先腐蚀,再膨胀
img_close = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)#cv2.MORPH_CLOSE 闭运算,先膨胀,再腐蚀

#对比
plt.subplot(121),plt.imshow(img_open),plt.title("OPEN")
plt.subplot(122),plt.imshow(img_close),plt.title("CLOSE")
plt.show()

cv2.waitKey(0)

 

现在我们看第二幅图像,这明显就没有把毛刺除去,因为先膨胀,毛刺也随之变大,再腐蚀的话毛刺就不会除干净了。 

六,梯度运算

形态学梯度运算是用图像的膨胀图像减腐蚀图像的操作,该操作可以获取原始图像中前景图像的边缘。

梯度 = dilate - erode

我们可以想象到图片应该是一个边框对吧?接下来我们来验证一下猜想。

1.代码示例

img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5, 5), np.uint8)
img_gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
plt.subplot(131),plt.imshow(img_gradient),plt.title("Gradient")
plt.show()

cv2.waitKey(0)

和我们的猜想差不多,不过比较可惜:毛刺没有去掉。我们可以先调用开运算再来一次梯度运算,应该就可以得到干净的边框吧?

img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5, 5), np.uint8)
img = cv2.erode(img,kernel,iterations=2)
img = cv2.dilate(img,kernel,iterations=2)
img_gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
plt.subplot(131),plt.imshow(img_gradient),plt.title("Gradient")
plt.show()

cv2.waitKey(0)

七,礼帽运算

礼帽运算是用原始图像减去其开运算图像的操作。礼帽运算能够获取图像的噪声信息,或者得到比原始图像的边缘更亮的边缘信息。

 我们再代码验证前可以想想:开运算图像相当于除去毛刺的原图像吧?所以用原图像减去开运算图像应该只剩毛刺对吗?

1.代码示例

img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5, 5), np.uint8)
img = cv2.erode(img,kernel,iterations=2)
img = cv2.dilate(img,kernel,iterations=2)
img_gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
img_tophat = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
plt.subplot(131),plt.imshow(img_gradient),plt.title("Gradient")
plt.subplot(132),plt.imshow(img_tophat),plt.title("TOPHAT")
plt.show()

cv2.waitKey(0)

为什么第二幅图像是空的?我们仔细观察代码发现,原来是我们之前已经对原图像进行过开运算操作了,所以相减后没有图像了。我们删除掉开运算处理的代码。

img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5, 5), np.uint8)
img_gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
img_tophat = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
plt.subplot(131),plt.imshow(img_gradient),plt.title("Gradient")
plt.subplot(132),plt.imshow(img_tophat),plt.title("TOPHAT")
plt.show()

cv2.waitKey(0)

这下和我们的预想是一致的。 

八,黑帽运算

黑帽运算是用闭运算图像减去原始图像的操作。黑帽运算能够获取图像内部的小孔,或前景色中的小黑点,或者得到比原始图像的边缘更暗的边缘部分。

 1.代码示例

img = cv2.imread('manolo_1.jpg')
kernel = np.ones((5, 5), np.uint8)
img_gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
img_tophat = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
img_blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
plt.subplot(131),plt.imshow(img_gradient),plt.title("Gradient")
plt.subplot(132),plt.imshow(img_tophat),plt.title("TOPHAT")
plt.subplot(133),plt.imshow(img_blackhat),plt.title("BLACKHAT")
plt.show()
cv2.waitKey(0)

图像效果并不是很明显,这个方法是用来显示原图像的噪声的,有余力可以用不同图片进行演示。 

九,核函数

在进行形态学操作时,必须使用一个特定的核(结构元)。该核可以自定义生成,也可以 通过函数 cv2.getStructuringElement()构造。函数 cv2.getStructuringElement()能够构造并返回一 个用于形态学处理所使用的结构元素。该函数的语法格式为:

                retval = cv2.getStructuringElement( shape, ksize[, anchor])

import cv2

kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
kernel2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
kernel3 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
print("kernel1=\n", kernel1)
print("kernel2=\n", kernel2)
print("kernel3=\n", kernel3)

这部分可以替代np.ones构建核的过程,通过不同的参数来设置不同的核,但是缺点是不能自定义。如果想要自己的卷积核,那还是用np自己构建吧。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/660305.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

番外篇 | YOLOv8改进之引入YOLOv9的RepNCSPELAN4模块 | 替换YOLOv8的C2f

前言:Hello大家好,我是小哥谈。YOLOv9,作为YOLO(You Only Look Once)系列的最新成员,代表着实时物体检测技术的又一重要里程碑。自YOLO系列算法诞生以来,它就以其出色的性能和简洁的设计思想赢得了广泛的关注和认可。从最初的YOLOv1到如今的YOLOv9,这个系列不断地进行技…

【学习Day2】计算机基础

✍🏻记录学习过程中的输出,坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞👍🏻收藏⭐评论✍🏻指点🙏 1.4 校验码 奇偶校验 ● 奇偶校验码的编码方法是: 由若干位有效信息的头部或者…

JAVA云HIS医院管理系统源码 云HIS系统源码 云HIS的优势 云HIS的发展

JAVA云HIS医院管理系统源码 云HIS系统源码 云HIS的优势 云HIS的发展 HIS系统,即医院信息系统(Hospital Information System),在医院的运营和管理中扮演着至关重要的角色。关于HIS系统的溯源,简单从以下几个方面进行讲…

失落的方舟 命运方舟台服封号严重 游戏封IP怎么办

步入《失落的方舟》(Lost Ark),这款由Smilegate精心打造的宏大规模在线角色扮演游戏(MMORPG),您将启程前往阿克拉西亚这片饱经沧桑的奇幻大陆,展开一场穿越时空的壮阔探索。在这里,一…

zabbix客户端启用ping脚本 , 采集结果返回服务端

1.Zabbix-agent配置 (1) 查看自定义配置的目录位置 # more /etc/zabbix/zabbix_agentd.conf (2) 将配置的脚本放在指定的目录下 # cd /etc/zabbix/zabbix_agentd.d # vi get_ping.conf UserParameter=get_ping[*], /bin/ping -c 1 -W 1 $1 &> /dev/null &a…

一文读懂Apollo客户端配置加载流程

本文基于 apollo-client 2.1.0 版本源码进行分析 Apollo 是携程开源的配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。 Apollo支持4个维度管理Key-Value格式的配…

「异步魔法:Python数据库交互的革命」(二)

哈喽,我是阿佑,上篇文章带领了大家跨入的异步魔法的大门——Python数据库交互,一场魔法与技术的奇幻之旅! 从基础概念到DB-API,再到ORM的高级魔法,我们一步步揭开了数据库操作的神秘面纱。SQLAlchemy和Djan…

如何使用 .htaccess 删除文件扩展名

本周有一个客户,购买Hostease的虚拟主机,询问我们的在线客服,如何使用 .htaccess 删除文件扩展名?我们为用户提供相关教程,用户很快解决了遇到的问题。在此,我们分享这个操作教程,希望可以对您有…

C# 数组/集合排序

一&#xff1a;基础类型集合排序 /// <summary> /// 排序 /// </summary> /// <param name"isReverse">顺序是否取反</param> public static void Sort<T>(this IList<T> array, bool isReverse false)where T : IComparable …

洗地机什么品牌质量好?家用洗地机排行榜

一年一度的大促节又到了&#xff0c;各大电商平台和实体店纷纷推出力度不小的折扣活动&#xff0c;吸引着消费者的关注和购买欲望。很多家庭也趁着这个机会&#xff0c;购置一些智能家居产品来提升生活品质。其中&#xff0c;洗地机作为近年来发展迅速的明星产品&#xff0c;受…

Mac安装tomcat

代码 brew install tomcat 运行结果如下&#xff1a; 如果要启动输入&#xff1a; brew services start tomcat

鸿蒙课程培训 | 讯方技术与鸿蒙生态服务公司签约,成为鸿蒙钻石服务商

3月15日&#xff0c;深圳市讯方技术股份有限公司与鸿蒙生态服务公司签署合作协议&#xff0c;讯方技术成为鸿蒙钻石服务商&#xff0c;正式进军鸿蒙原生应用培训开发领域。讯方技术总裁刘国锋、副总经理刘铭皓、深圳区域总经理张松柏、深圳区域交付总监张梁出席签约仪式。 作…

【全开源】防伪溯源一体化管理系统源码(FastAdmin+ThinkPHP和Uniapp)

一款基于FastAdminThinkPHP和Uniapp进行开发的多平台&#xff08;微信小程序、H5网页&#xff09;溯源、防伪、管理一体化独立系统&#xff0c;拥有强大的防伪码和溯源码双码生成功能&#xff08;内置多种生成规则&#xff09;、批量大量导出防伪和溯源码码数据、支持代理商管理…

3D模型展示适合哪些类型的产品?

3D模型展示特别适合那些需要全面展示产品细节和特性的商品&#xff0c;产品3D交互展示具有直观性、动态性、交互性等显著优势&#xff0c;可以通过51建模网一站式完成商品3D建模、3D展示、3D定制、AR试穿等功能&#xff0c;以下是一些适合使用3D模型展示的产品类型&#xff1a;…

低代码开发难吗?

在软件开发的多样化浪潮中&#xff0c;低代码开发平台以其简化的编程模型&#xff0c;为IT行业带来了新的活力。作为一位资深的IT技术员&#xff0c;我对低代码开发平台的易用性和强大功能有着深刻的认识。今天&#xff0c;我将分享我对YDUIbuilder这一免费开源低代码平台的使用…

29-ESP32-S3-WIFI_Driver-00 STA模式扫描全部 AP

ESP32-S3 WIFI_Driver 引言 ESP32-S3是一款集成了Wi-Fi和蓝牙功能的芯片。关于WIFI的部分&#xff0c;其实内容比我想象的要多得多。所以通常来说&#xff0c;如果你想要编写自己的Wi-Fi应用程序&#xff0c;最快捷的方法就是先找一个类似的示例应用&#xff0c;然后将它的相…

图片去水印工具(低调用哦)

一、简介 1、它是一款专业的图像编辑工具&#xff0c;旨在帮助用户轻松去除照片中不需要的元素或修复照片中的缺陷。无论是修复旧照片、消除拍摄时的不良构图&#xff0c;还是删除照片中的杂乱元素&#xff0c;都能帮助用户快速实现这些目标。其功能强大且操作简单&#xff0c…

继承--5.29

继承格式&#xff1a; package javatest2;public class people {int age;double workday;public people(int age, double workday) {this.age age;this.workday workday;} }package javatest2;public class student extends people {int studyday;public student(int age, d…

使用目标检测模型YOLO V9 OBB进行旋转目标的检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)

我看到YOLO V8中&#xff08;ultralytics版本8.2.18&#xff09;集成了YOLO V9&#xff0c;所以直接在YOLO V8 OBB的基础上实现YOLO V9 OBB&#xff0c;训练结果也出来了&#xff0c;但是评估指标比YOLO V8 OBB低一点点&#xff0c;不知道是不是哪里遗漏修改了......如有大神赐…

MAC M1 —— Install

文章目录 MAC M1 —— Install安装IDEA安装JDK安装Maven安装brew无法创建文件 /data/serverMac 修改终端用户名&#xff08;主机名&#xff09;PyCharm MAC M1 —— Install 安装IDEA 关键词&#xff1a;2020到2021.3的激活步骤。找下Download文件夹 安装JDK 在个人的电脑上…