OpenCV:入门(四)

news2024/11/16 23:59:46

形态学操作

形态学,即数学形态学(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自己构建吧。 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

花钱学谢宁DOE培训,投入产出比到底如何?

在当今这个快速发展的时代,无论是职场人士还是创业者,都渴望通过不断学习来提升自我能力,以便在竞争激烈的市场中脱颖而出。其中,谢宁DOE培训因其独特的理念和方法,吸引了众多求学者的目光。然而,面对不菲的…

从零开始利用MATLAB进行FPGA设计(六)用ADC采集信号教程1

黑金的教程做的实在太拉闸了,于是自己摸索信号采集模块的使用方法。 ADC模块:AN9238 FPGA开发板:AX7020;Xilinx 公司的 Zynq7000 系列的芯片XC7Z020-2CLG400I,400引脚 FBGA 封装。 往期回顾: 从零开始利…

Vue项目运行页面禁止缩放【移动端和PC端都禁止缩放】解决方案

Vue项目运行页面禁止缩放【移动端和PC端都禁止缩放】解决方案,有的人手很J,总喜欢放大缩小,从而会导致页面错乱,以下是解决方案,简单有效 效果图PC:滚轮缩放和其他缩放都会禁止 移动端效果图:各种手机平板…

Python数据处理,使用 tkinter 模块点击获取文件目录

Python数据处理,使用 tkinter 模块点击获取文件目录 正文 正文 当我们进行数据处理读取文件内数据的时候,通常,我们需要设定好一个存放当前文件所在目录的变量。比如如下目录: file_path rC:\Users\xxx\Desktop\DataSet\Data.c…

20240528解决飞凌的OK3588-C的核心板的TYPE-C1接口识别问题

20240528解决飞凌的OK3588-C的核心板的TYPE-C1接口识别问题 2024/5/28 16:46 缘起: 现阶段碰到的USB相关的问题:(LINUX R4版本) 1、USB3.0插USB摄像头 lsusb找不到设备 2、刷机口只接了3根线,GND/D/D-,可以…

vue3 + ts 实现IP地址及Mac地址输入框功能

1、组件完成代码 <template><div class"ip-input"><div v-for"(item, index) in ipArr" :key"index" class"ip-input__item-wrap"><input ref"ipInput" v-model"ipArr[index]" type"t…

Python装饰器的应用

Python 中的装饰器是一种语法糖&#xff0c;可以在运行时&#xff0c;动态的给函数或类添加功能。装饰器本质上是一个函数&#xff0c;使用 函数名就是可实现绑定给函数的第二个功能 。它的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。 …

清华大学提出IFT对齐算法,打破SFT与RLHF局限性

监督微调&#xff08;Supervised Fine-Tuning, SFT&#xff09;和基于人类反馈的强化学习&#xff08;Reinforcement Learning from Human Feedback, RLHF&#xff09;是预训练后提升语言模型能力的两大基础流程&#xff0c;其目标是使模型更贴近人类的偏好和需求。 考虑到监督…

奥利奥罚单背后的启示:企业合规与反垄断的边界

在全球化的经济环境中&#xff0c;企业面临着激烈的市场竞争。为了在竞争中脱颖而出&#xff0c;一些企业可能会采取不正当的竞争手段&#xff0c;如垄断、价格歧视等。然而&#xff0c;这些行为往往会触犯反垄断法规&#xff0c;给企业带来严重的法律风险。最近&#xff0c;奥…

jsp音乐网站的设计与实现

需求收集 经过与客户探讨后 得到初步的活动图,此活动图叙述了游客、会员、管理员在网站的活动得到初步的类图得到网站功能包图得到用例图 ●活动图 ●初步的类图 注&#xff1a;为得到良好的安全性&#xff0c;登入管理员的时候&#xff0c;应该再输入管理员密码.所以在admin…

AI联想扩图解决方案,智能联想,无需人工干预

对于众多企业而言&#xff0c;无论是广告宣传、产品展示还是客户体验&#xff0c;高质量、宽广视野的图像都是不可或缺的。受限于车载摄像头等设备的物理限制&#xff0c;我们往往难以捕捉到完整、宽广的视觉场景。针对这一挑战&#xff0c;美摄科技凭借其前沿的AI联想扩图解决…

Vue3实战笔记(50)—Vue 3+ECharts还能看股票?附源码

文章目录 前言一、改进之前的封装echarts组件二、封装股票k线图总结 前言 今天封装股票k线图组件 前几天学的几个知识点都有用到&#xff0c;都是在封装k线图的时候遇到的问题&#xff0c;又啃了一遍基础。 一、改进之前的封装echarts组件 使用ref对象方式封装useEChartsRef.t…

git 学习随笔

git 学习随笔 基本概念 git 对待数据类似快照流的形式而不是类似 cvs 那样的纪录文件随时间逐步积累的差异 git 中所有数据在存储钱都会计算校验和&#xff08;hash) 三种状态&#xff1a;已提交(committed)&#xff0c;已修改(modified)&#xff0c;已暂存(staged)。 add…

计算机图形学入门03:二维变换

变换(Transformation)可分为模型(Model)变换和视图(Viewing)变换。在3D虚拟场景中相机的移动和旋转&#xff0c;角色人物动画都需要变换&#xff0c;用来描述物体运动。将三维世界投影变换到2D屏幕上成像出来&#xff0c;也需要变换。 1.缩放变换 缩放(Scale)变换&#xff1a; …

电脑提示:“找不到vcruntime140_1.dll无法执行”该怎么恢复?一键修复vcruntime140_1.dll丢失

vcruntime140_1.dll是一个关键的系统文件&#xff0c;它在电脑运行过程中被调用。如果该文件丢失或找不到&#xff0c;将会导致弹出"找不到vcruntime140_1.dll无法执行"的错误提示。缺失vcruntime140_1.dll文件将导致软件或游戏无法正常打开或运行。 一键修复vcrunti…

沃飞长空总部落地成都高新,为蓉低空经济发展助力!

5月25日&#xff0c;吉利科技集团与成都高新区签署合作协议&#xff0c;吉利科技集团旗下沃飞长空全球总部落地成都高新区。 根据协议&#xff0c;沃飞长空全球总部项目落地成都未来科技城&#xff0c;将布局总部办公、研发和生产制造低空出行航空器等业务。双方将积极发挥各自…

微信图片识别文字怎么弄?介绍三个识别方法

微信图片识别文字怎么弄&#xff1f;在信息爆炸的时代&#xff0c;我们每天都会接触到大量的图片信息&#xff0c;其中包含的文字内容往往是我们获取信息的重要途径。然而&#xff0c;手动输入图片中的文字既费时又费力&#xff0c;这时&#xff0c;一款能够准确识别微信图片中…

量化交易入门:如何在QMT中配置Python环境,安装第三方依赖包

哈喽,大家好,我是木头左! 引言 QMT,作为量化交易系统中的佼佼者,以其强大的功能和灵活的操作性,受到了广大投资者的青睐。但是,对于很多新手来说,如何在QMT中配置Python环境,安装第三方依赖包,却是一个让人头疼的问题。本文将从零开始,手把手教你如何在QMT中配置Py…

【NumPy】全面解析subtract函数:高效数组减法指南

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

游戏联运平台如何助力游戏行业飞速发展?

随着科技的进步和互联网的普及&#xff0c;游戏行业正以前所未有的速度飞速发展。在这个过程中&#xff0c;游戏联运平台凭借其独特的优势和功能&#xff0c;成为了推动游戏行业腾飞的关键力量。本文将探讨游戏联运平台如何助力游戏行业实现飞速发展。 一、游戏联运平台的定义与…