【OpenCV入门】第六部分——腐蚀与膨胀

news2025/2/25 17:27:03

文章结构

  • 腐蚀
  • 膨胀
  • 开运算
  • 闭运算
  • 形态学方法
    • 梯度运算
    • 顶帽运算
    • 黑帽运算

腐蚀

腐蚀操作可以让图像沿着自己的边界向内收缩。OpenCV通过”核“来实现收缩计算。“核”在形态学中可以理解为”由n个像素组成的像素块“,像素块包含一个核心(通常在中央位置,也可以定义在其他位置)。像素块会在图像的边缘移动,在移动过程中,核会将图像边缘那些与核重合但又没有越过核心的像素点都抹除,效果如下:

在这里插入图片描述

OpenCV将腐蚀操作封装成了erode()方法:

dst = ccv2.erode(src, kernel, anchor, iterations, borderType, borderValue)
  • src: 原始图像
  • kernel: 腐蚀使用的核
  • anchor:(可选)核的锚点位置
  • iteration:(可选)腐蚀操作的迭代次数,默认值为1
  • borderType:(可选)边界样式,建议默认
  • borderValue:(可选)边界值,建议默认
  • dst :经过腐蚀之后的图像

在OpenCV做腐蚀或其他形态学操作时,通常使用NumPy模块来创建核数组,例如:

import numpy as np
k = np.ones((5,5), np.uint8)

这两行代码创建了一个数组,可以当作erode()方法的核参数。除了5×5的结构,还可以使用3×3、9×9等其他结构,行列数越大,计算出来的效果就越粗糙,行列数越小,计算出的效果就越精细。

实例1: 将仙人球图像中的刺都抹除掉

import cv2
import numpy as np
img = cv2.imread("cactus.jpg")  # 读取原图
k = np.ones((3, 3), np.uint8)  # 创建3*3的数组作为核
cv2.imshow("img", img)  # 显示原图
dst = cv2.erode(img, k)  # 腐蚀操作
cv2.imshow("dst", dst)  # 显示腐蚀效果
cv2.waitKey()  # 按下任何键盘按键后
cv2.destroyAllWindows()  # 释放所有窗体

结果如下:

在这里插入图片描述
如果是(1,1),等于没削;如果是(5,5),直接削皮了。

膨胀

膨胀操作与腐蚀操作正好相反,膨胀操作可以让图像沿着自己的边界向外扩张。同样是通过核计算,当核在图像的边缘移动时,核会将图像边缘填补新的像素,效果如下:

dst = cv2.dilate(src, kernel, anchor, iterations, borderType, borderValue)
  • src: 原始图像
  • kernel: 膨胀使用的核
  • iteration:(可选)膨胀操作的迭代次数,默认值为1
  • borderType:(可选)边界样式,建议默认
  • borderValue:(可选)边界值,建议默认
  • dst :经过膨胀之后的图像

实例2: 将图像加工成”近视眼“效果

import cv2
import numpy as np
img = cv2.imread("sunset.jpg")  # 读取原图
k = np.ones((9, 9), np.uint8)  # 创建9*9的数组作为核
cv2.imshow("img", img)  # 显示原图
dst = cv2.dilate(img, k)  # 膨胀操作
cv2.imshow("dst", dst)  # 显示膨胀效果
cv2.waitKey()  # 按下任何键盘按键后
cv2.destroyAllWindows()  # 释放所有窗体

结果如下:
在这里插入图片描述

开运算

开运算就是先将图像进行腐蚀操作,再进行膨胀操作。开运算可以用来抹除图像外部的细节(或者噪声)

例如图 7.13 是一个简单的二叉树,父子节点之间都有线连接。如果对此图像进行腐蚀操作,可以得出如图 7.14 所示的图像,连接线消失了,节点也比原图节点小一圈。此时再执行膨胀操作,让缩小的节点膨胀回原来的大小,就得出了如图 7.15 所示的效果。
在这里插入图片描述
这三张图就是开运算的过程,从结果可以明显地看出: 经过开运算之后,二叉树中的连接线消失了,只剩下光秃秃的节点。因为连接线被核当成“细节”抹除了,所以利用检测轮廓的方法就可以统计出二叉树节点数量,也就是说在某些情况下,开运算的结果还可以用来做数量统计。

实例3: 抹除黑种草图像中的针状叶子

import cv2
import numpy as np
img = cv2.imread("nigella.png")  # 读取原图
k = np.ones((5, 5), np.uint8)  # 创建5*5的数组作为核
cv2.imshow("img", img)  # 显示原图
dst = cv2.erode(img, k)  # 腐蚀操作
dst = cv2.dilate(dst, k)  # 膨胀操作
cv2.imshow("dst", dst)  # 显示开运算结果
cv2.waitKey()  # 按下任何键盘按键后
cv2.destroyAllWindows()  # 释放所有窗体

结果如下:
在这里插入图片描述

闭运算

闭运算就是将图像先进行膨胀操作,再进行腐蚀操作。闭运算可以抹除图像内部的细节(或者噪声)。

例如图 7.19 是一个身上布满斑点的小蜘蛛,这些斑点就是图像的内部细节。先将图像进行膨胀操作,小蜘蛛身上的斑点 (包括小眼睛)就被抹除掉,效果如图 7.20 所示。然后再将图像进行腐蚀操作,让膨胀的小蜘蛛缩回原来的大小,效果如图 7.21 所示。

在这里插入图片描述
闭运算除了会抹除图像内部的细节,还会让一些里的较近的区域合并成一块区域。

形态学方法

OpenCV提供了一个morphologyEx()形态学方法,包含了所有常用的运算。

dst = cv2.morphologyEx(src, op, kernel, anchor, iterations, borderType, borderValue)
  • src: 原始图像
  • op: 操作类型
参数值含义
cv2.MORPH_ERODE腐蚀操作
cv2.MORPH_DILATE膨胀操作
cv2.MORPH_OPEN开运算,先腐蚀后膨胀
cv2.MORPH_CLOSE闭运算,先膨胀后腐蚀
cv2.MORPH_GRADIENT梯度运算,膨胀图减腐蚀图,可以得出简易的轮廓
cv2.MORPH_TOPHAT顶帽运算,原始图像减开运算图像
cv2.MORPH_BLACKHAT黑帽运算,闭运算图像减原始图像
  • kernel: 操作过程中所使用的核
  • anchor:(可选),核的锚点位置
  • iteration:(可选)操作的迭代次数,默认值为1
  • borderType:(可选)边界样式,建议默认
  • borderValue:(可选)边界值,建议默认
  • dst :操作之后得到的图像

梯度运算

这里的梯度指的是图像梯度,可以简单地理解为像素的变化程度。几个连续的像素,其像素值跨度越大,则梯度值越大。

梯度运算就是让原图的膨胀图像减去原图的腐蚀图像。因为膨胀图比原图大,腐蚀图像比原图小,利用腐蚀图像将膨胀图像掏空,就得到了原图的 轮廓图像(大概,并不精准)。
在这里插入图片描述

实例4: 通过梯度运算画出小蜘蛛的轮廓

import cv2
import numpy as np
img = cv2.imread("spider.png")  # 读取原图
k = np.ones((5,5), np.uint8)  # 创建5*5的数组作为核
cv2.imshow("img", img)  # 显示原图
dst = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, k) # 进行梯度运算
cv2.imshow("dst", dst)  # 显示梯度运算结果
cv2.waitKey()  # 按下任何键盘按键后
cv2.destroyAllWindows()  # 释放所有窗体

结果如下:

在这里插入图片描述

顶帽运算

顶帽运算就是让原图减去原图的开运算图像,得到图像的外部细节

实例5: 通过顶帽运算画出小蜘蛛的腿

import cv2
import numpy as np
img = cv2.imread("spider.png")  # 读取原图
k = np.ones((5, 5), np.uint8)  # 创建5*5的数组作为核
cv2.imshow("img", img)  # 显示原图
dst = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, k)  # 进行顶帽运算
cv2.imshow("dst", dst)  # 显示顶帽运算结果
cv2.waitKey()  # 按下任何键盘按键后
cv2.destroyAllWindows()  # 释放所有窗体

结果如下:

在这里插入图片描述

黑帽运算

黑帽运算就是让原图的闭运算图像减去原图,得到原图像的内部细节

实例6: 通过黑帽运算画出小蜘蛛身上的花纹

import cv2
import numpy as np
img = cv2.imread("spider2.png")  # 读取原图
k = np.ones((5, 5), np.uint8)  # 创建5*5的数组作为核
cv2.imshow("img", img)  # 显示原图
dst = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, k)  # 进行黑帽运算
cv2.imshow("dst", dst)  # 显示黑帽运算结果
cv2.waitKey()  # 按下任何键盘按键后
cv2.destroyAllWindows()  # 释放所有窗体

结果如下:

在这里插入图片描述

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

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

相关文章

leetcode 1326. Minimum Number of Taps to Open to Water a Garden

x轴上的花园范围为[0,n], 0~n这个n1个离散点上有水龙头,第 i 个水龙头能浇水的范围为[i-ranges[i], iranges[i]]. 求能浇整个花园的最小水龙头个数。 思路: 方法一: greedy 先把每个水龙头能浇的区间准备好, 用一个数组保存所有…

Node.js 应用的御用品: Node.js 错误处理系统

开发中,有些开发者会积极寻求处理错误,力求减少开发时间,但也有些人完全忽略了错误的存在。正确处理错误不仅意味着能够轻松发现和纠正错误,而且还意味着能够为大型应用程序开发出稳健的代码库。 特别是对于 Node.js 开发人员&am…

uniapp项目实践总结(六)自定义顶部导航栏

本篇主要讲述如何自定义顶部导航栏,有时候默认导航栏不足以满足我们的需求,这时候就需要自定义导航栏来解决这个问题。 目录 默认导航修改配置自定义顶部默认导航 自带的默认顶部导航设置的内容有限,不容易扩展修改,因此如果有更加个性化的需求,则需要自定义顶部导航。 …

中文句子关系推断

本文通过ChnSentiCorp数据集介绍了中文句子关系推断任务过程,主要使用预训练语言模型bert-base-chinese直接在测试集上进行测试,也简要介绍了模型训练流程,不过最后没有保存训练好的模型。 一.任务简介和数据集 通过模型来判断2个句子是否连…

Gazebo仿真环境下的强化学习实现

Gazebo仿真环境下的强化学习实现 主体源码参照《Goal-Driven Autonomous Exploration Through Deep Reinforcement Learning》 文章目录 Gazebo仿真环境下的强化学习实现1. 源码拉取2. 强化学习实现2.1 环境2.2 动作空间2.3 状态空间2.4 奖励空间2.5 TD3训练 3. 总结 1. 源码…

【LeetCode算法系列题解】第41~45题

CONTENTS LeetCode 41. 缺失的第一个正数(困难)LeetCode 42. 接雨水(困难)LeetCode 43. 字符串相乘(中等)LeetCode 44. 通配符匹配(困难)LeetCode 45. 跳跃游戏 II(中等&…

字符和字符串的库函数模拟与实现

前言: 相信大家平常在写代码的时候,用代码解决实际问题时苦于某种功能的实现,而望而止步,这个时候库函数的好处就体现出来了,当然个人代码编写能力强的可以自己创建一个函数,不过相当于库函数来说却是浪费了…

SSM 基于注解的整合实现

一、pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelV…

C++的基类和派生类构造函数

基类的成员函数可以被继承&#xff0c;可以通过派生类的对象访问&#xff0c;但这仅仅指的是普通的成员函数&#xff0c;类的构造函数不能被继承。构造函数不能被继承是有道理的&#xff0c;因为即使继承了&#xff0c;它的名字和派生类的名字也不一样&#xff0c;不能成为派生…

CSC2121A

半桥架构的栅极驱动电路CSC2121A CSC2121系列是一款高性价比的半桥架构的栅极驱动专用电路&#xff0c;用于大功率MOS管、IGBT管栅极驱动。IC内部集成了逻辑信号处理电路、死区时间控制电路、欠压保护电路、电平位移电路、脉冲滤波电路及输出驱动电路&#xff0c;专用于无刷电…

ClickHouse配置Hdfs存储数据

文章目录 背景配置单机配置HA高可用Hdfs集群参考文档 背景 由于公司初始使用Hadoop这一套&#xff0c;所以希望ClickHouse也能使用Hdfs作为存储 看了下ClickHouse的文档&#xff0c;拿Hdfs举例来说&#xff0c;有两种方式来完成&#xff0c;一种是直接关联Hdfs上的数据文件&am…

【python爬虫案例】用python爬豆瓣音乐TOP250排行榜!

文章目录 一、爬虫对象-豆瓣音乐TOP250二、python爬虫代码讲解三、同步视频四、获取完整源码 一、爬虫对象-豆瓣音乐TOP250 您好&#xff0c;我是 马哥python说 &#xff0c;一名10年程序猿。 今天我们分享一期python爬虫案例讲解。爬取对象是&#xff0c;豆瓣音乐TOP250排行…

汇报下卢松松自媒体收入情况

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 9月1日了&#xff0c;2023年还剩最后4个月了&#xff0c;怎么样?梦想是不是越来越远了? 我看很多人都在涌入做自媒体行业&#xff0c;那今天卢松松就给大家汇报下近期卢松松自媒体帐号的收益情况…

2023开学礼《乡村振兴战略下传统村落文化旅游设计》南京农大许少辉八一新书

2023开学礼《乡村振兴战略下传统村落文化旅游设计》南京农大许少辉八一新书

MVC、MVP、MVVM的成本角度结合业务,如何考虑选型?一文了解方方面面

大家都知道&#xff0c;使用架构的目的是使程序模块化&#xff0c;做到模块内部的高聚合和模块之间的低耦合&#xff0c;使得程序在开发的过程中&#xff0c;开发人员只需要专注于一点&#xff0c;提高程序开发的效率。那么MVC、MVP、MVVM&#xff0c;该怎么选&#xff1f;在什…

百万级并发IM即时消息系统(2)

1.用户model type UserBasic struct {gorm.ModelName stringPassWord stringPhone string valid:"matches(^1[3-9]{1}\\d{9}$)"Email string valid:"email"Avatar string //头像Identity stringClientIp s…

Java注解和反射

注解(Java.Annotation) 什么是注解&#xff08;Annotation&#xff09;&#xff1f; Annotation是从JDK5.0开始引入的新技术 Annotation的作用: 不是程序本身&#xff0c;可以对程序作出解释(这一点和注释(comment)没什么区别)可以被其他程序(比如:编译器等)读取Annotation的…

解决uniapp下拉框 内容被覆盖的问题

1. 下拉框 内容被覆盖的问题 场景: 现在是下拉框被表格覆盖了 解决办法: 在表格上添加css 样式来解决这个问题 .add-table{display: static;overflow: visible; } display: static: 将元素会按照默认的布局方式进行显示&#xff0c;不会分为块状或行内元素。 overflow: vi…

【力扣每日一题】2023.9.1 买钢笔和铅笔的方案数

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们三个数&#xff0c;一个是我们拥有的钱&#xff0c;一个是钢笔的价格&#xff0c;另一个是铅笔的价格。 问我们一共有几种买笔…

需求管理系统大盘点,谁能问鼎行业王者宝座?

“需求管理系统有哪些&#xff1f;这些品牌引领行业新风潮&#xff1a;Zoho Projects、SAP SuccessFactors、Oracle NetSuite、Microsoft Dynamics 365、Infor CloudSuite、JDA Software。” 需求管理系统是一种专门用于收集、分析和跟踪客户需求的工具&#xff0c;可以帮助企业…