11.1图像的腐蚀和膨胀

基本概念-图像腐蚀

图像腐蚀是一种用于去除图像中小的对象或者突出物体边缘的形态学操作。

图像腐蚀(erosion)的基本概念
图像腐蚀通常用于二值图像,其基本原理是从图像中“侵蚀”掉一些像素点,这些像素点通常是边界上的或者是孤立的小点。在二值图像中,通常用白色表示前景,黑色表示背景。腐蚀操作会使得前景区域缩小。

腐蚀操作可以用一个称为结构元素(或核)的小矩阵来定义。这个结构元素通常是对称的,并且中心像素是结构元素的位置。腐蚀过程检查结构元素覆盖下的每个像素是否都为前景像素(通常是白色),只有当所有像素都是前景像素时,中心像素才会保留为前景;否则,中心像素将被标记为背景(通常是黑色)。

图像腐蚀(Erosion)是形态学操作的一种基本形式,主要用于消除小对象、分离相邻物体以及平滑边界。腐蚀操作通常用于图像预处理阶段,如去噪、连接组件的分离等。

形态学腐蚀原理

腐蚀操作的基本思想是从图像中去除突出的小部分或“凸起”的部分。具体来说,腐蚀会从每个前景像素(通常为白色或非零值)中减去一个结构元素(Structuring Element)的尺寸,如果结构元素在该像素周围的所有位置都能完全包含在前景区域内,则该像素被认为是腐蚀操作的结果的一部分。

结构元素

结构元素(Structuring Element)是一个定义了如何进行腐蚀操作的小型网格。最常见的结构元素是一个3x3或更大的方形网格,其中心像素代表当前正在处理的图像中的像素。结构元素可以有不同的形状,如圆形、十字形、椭圆形等。

腐蚀操作

在OpenCV中,可以使用erode函数来执行图像的腐蚀操作。

函数原型

void erode(InputArray src,OutputArray dst,InputArray kernel,Point anchor = Point(-1,-1),int iterations = 1,double borderType = BORDER_CONSTANT,const Scalar& borderValue = morphologyDefaultBorderValue()
);参数说明
•src:输入图像。
•dst:输出图像,与输入图像具有相同的大小和类型。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
•iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。
•borderValue:边界值,默认为morphologyDefaultBorderValue()。

示例代码1

下面是一个使用OpenCV C++实现图像腐蚀的示例代码:

#include "pch.h"#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;void erodeImage(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{erode(src, dst, kernel, Point(-1, -1), iterations);
}int main(int argc, char** argv)
{/*if (argc != 2){cout << "Usage: ./ErodeImage <Image Path>" << endl;return -1;}*/// 加载图像Mat img = imread("897.png", IMREAD_GRAYSCALE);if (!img.data) {cout << "Error opening image" << endl;return -1;}// 定义结构元素Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));// 初始化输出矩阵Mat eroded;// 执行腐蚀操作erodeImage(img, eroded, kernel, 1);// 显示结果namedWindow("Origal Imagine", WINDOW_NORMAL);imshow("Origal Imagine", img);namedWindow("Eroded Image", WINDOW_NORMAL);imshow("Eroded Image", eroded);waitKey(0);destroyAllWindows();return 0;
}代码解释
1. 加载图像:使用 imread 函数以灰度模式加载图像。
2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
3. 初始化输出矩阵:创建一个新的矩阵来存储腐蚀后的图像。
4. 执行腐蚀操作:使用 erode 函数对图像进行腐蚀操作。
5. 显示结果:使用 imshow 函数显示原始图像和腐蚀后的图像。注意事项
•结构元素的形状:不同的结构元素形状会导致不同的腐蚀效果。矩形结构元素通常用于去除孤立的噪声点,而十字形结构元素则可能更适合于特定的应用场景。
•迭代次数:增加迭代次数会使腐蚀效果更加明显,但过度的腐蚀可能会导致有用的细节丢失。
•边界处理:腐蚀操作默认会处理图像的边界,可以选择不同的边界处理方式来影响腐蚀的效果。
•数据类型:确保输出图像的数据类型与输入图像相同。

运行结果1

应用场景

•去噪:在二值化图像或边缘检测之后,可以使用腐蚀操作去除小的孤立噪声点。

•分离连通组件:在处理连通组件时,可以使用腐蚀操作来分离紧密相连的对象。

•平滑边界:可以使用腐蚀操作来平滑图像的边界,使其更加光滑。

通过这些示例和详细解释,你应该能够理解如何在OpenCV中使用C++实现图像的腐蚀操作。

示例代码2

在OpenCV中,使用erode函数可以很方便地对图像进行腐蚀操作。下面是一个简单的例子,展示了如何使用C++来实现图像腐蚀:

#include "pch.h"#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;int main(int argc, char** argv)
{// 加载图像cv::Mat src = cv::imread("888.png", cv::IMREAD_GRAYSCALE);if (src.empty()){std::cout << "Error: Image cannot be loaded!" << std::endl;return -1;}// 定义结构元素cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));// 腐蚀图像cv::Mat dst;cv::erode(src, dst, element);// 显示结果cv::namedWindow("Original Image", cv::WINDOW_NORMAL);cv::imshow("Original Image", src);cv::namedWindow("Eroded Image", cv::WINDOW_NORMAL);cv::imshow("Eroded Image", dst);// 等待按键并退出cv::waitKey(0);return 0;
}在这个例子中:使用cv::imread读取图片。
使用cv::getStructuringElement创建一个3x3大小的矩形结构元素。
使用cv::erode函数对原图像进行腐蚀。
使用cv::imshow显示原始图像和腐蚀后的图像。腐蚀的程度取决于结构元素的形状和大小。不同的形状(如圆形、十字形等)以及更大的尺寸都会影响腐蚀的效果。如果需要更精细的控制,可以调整结构元素的大小和形状。

运行结果2

基本概念-图像膨胀

图像膨胀(dilation)是另一种常用的形态学操作,它与图像腐蚀相对。膨胀主要用于扩展图像中的对象边界,填补前景物体中的小孔洞,或者连接靠近的物体。在二值图像处理中,膨胀通常会使得前景区域扩大。

图像膨胀(Dilation)是形态学操作的一种基本形式,主要用于扩大前景区域(通常为白色或非零值),填补孔洞,连接接近的物体,并扩展边界。膨胀操作通常用于图像处理和分析中,如去噪、连接组件的合并等。

形态学膨胀原理

膨胀操作的基本思想是在每个前景像素周围加上一个结构元素(Structuring Element),如果结构元素中的任何部分落在前景区域内,则该像素被认为是膨胀操作的结果的一部分。

图像膨胀的基本概念
与腐蚀相反,膨胀操作同样需要一个结构元素。对于每个像素位置,如果结构元素覆盖下的任何像素是前景像素(通常是白色),那么中心像素也会被标记为前景。因此,膨胀可以增加前景区域的大小,使得边界向外扩张。

结构元素

结构元素是一个定义了如何进行膨胀操作的小型网格。最常见的结构元素是一个3x3或更大的方形网格,其中心像素代表当前正在处理的图像中的像素。结构元素可以有不同的形状,如圆形、十字形、椭圆形等。

膨胀操作

在OpenCV中,可以使用dilate函数来执行图像的膨胀操作。这个函数接受几个参数,包括输入图像、输出图像、结构元素、锚点位置、迭代次数等。

函数原型

void dilate(InputArray src,OutputArray dst,InputArray kernel,Point anchor = Point(-1,-1),int iterations = 1,double borderType = BORDER_CONSTANT,const Scalar& borderValue = morphologyDefaultBorderValue()
);参数说明
•src:输入图像。
•dst:输出图像,与输入图像具有相同的大小和类型。
•kernel:结构元素,可以使用getStructuringElement函数生成。
•anchor:结构元素相对于原点的位置,默认为中心位置。
•iterations:迭代次数,默认为1次。
•borderType:边界处理类型,默认为BORDER_CONSTANT。•borderValue:边界值,默认为morphologyDefaultBorderValue()。

示例代码3

下面是一个使用OpenCV C++实现图像膨胀的示例代码:

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;void dilateImage(const Mat &src, Mat &dst, const Mat &kernel, int iterations)
{dilate(src, dst, kernel, Point(-1, -1), iterations);
}int main(int argc, char** argv) 
{/*if (argc != 2) {cout << "Usage: ./DilateImage <Image Path>" << endl;return -1;}*/// 加载图像Mat img = imread("999.png", IMREAD_GRAYSCALE);if (!img.data){cout << "Error opening image" << endl;return -1;}// 定义结构元素Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));// 初始化输出矩阵Mat dilated;// 执行膨胀操作dilateImage(img, dilated, kernel, 1);// 显示结果namedWindow("Original Image", cv::WINDOW_NORMAL);imshow("Original Image", img);namedWindow("Dilated Image", cv::WINDOW_NORMAL);imshow("Dilated Image", dilated);waitKey(0);destroyAllWindows();return 0;
}代码解释
1. 加载图像:使用 imread 函数以灰度模式加载图像。
2. 定义结构元素:使用 getStructuringElement 函数生成一个3x3大小的矩形结构元素。
3. 初始化输出矩阵:创建一个新的矩阵来存储膨胀后的图像。
4. 执行膨胀操作:使用 dilate 函数对图像进行膨胀操作。
5. 显示结果:使用 imshow 函数显示原始图像和膨胀后的图像。注意事项
•结构元素的形状:不同的结构元素形状会导致不同的膨胀效果。矩形结构元素通常用于扩大前景区域,而十字形结构元素则可能适合特定的应用场景。
•迭代次数:增加迭代次数会使膨胀效果更加明显,但过度的膨胀可能会导致前景区域过大,甚至连接本来应该分离的物体。
•边界处理:膨胀操作默认会处理图像的边界,可以选择不同的边界处理方式来影响膨胀的效果。
•数据类型:确保输出图像的数据类型与输入图像相同。应用场景
•去噪:在二值化图像或边缘检测之后,可以使用膨胀操作去除小的孔洞或连接分离的物体。
•连接连通组件:在处理连通组件时,可以使用膨胀操作来连接紧密相连的对象。
•平滑边界:可以使用膨胀操作来平滑图像的边界,使其更加光滑。

运行结果3

示例代码4

在OpenCV中,使用dilate函数可以实现图像的膨胀操作。下面是一个简单的示例代码,展示了如何使用C++来实现图像膨胀:

#include "pch.h"#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;
using namespace cv;int main(int argc, char** argv)
{// 加载图像cv::Mat src = cv::imread("875.jpeg", cv::IMREAD_GRAYSCALE);if (src.empty()){std::cout << "Error: Image cannot be loaded!" << std::endl;return -1;}// 定义结构元素cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));// 膨胀图像cv::Mat dst;cv::dilate(src, dst, element);// 显示结果cv::namedWindow("Original Image", cv::WINDOW_NORMAL);cv::imshow("Original Image", src);cv::namedWindow("Dilated Image", cv::WINDOW_NORMAL);cv::imshow("Dilated Image", dst);// 等待按键并退出cv::waitKey(0);return 0;
}在这个例子中:cv::imread用于读取图片。
cv::getStructuringElement用于创建一个3x3大小的矩形结构元素。
cv::dilate函数用来执行膨胀操作。
cv::imshow用于显示原始图像和膨胀后的图像。结构元素的选择
结构元素的选择会影响膨胀的结果。常见的结构元素形状有矩形、椭圆和十字形等。结构元素的大小也会影响最终的效果。较大的结构元素会导致更大的膨胀效果,可能会合并原本分离的物体。迭代次数
在调用cv::dilate函数时,还可以指定迭代次数,这决定了膨胀操作被执行的次数。每次迭代都会根据结构元素再次扩展前景区域。更多的迭代次数意味着更大的膨胀效果。注意事项
膨胀和腐蚀都是针对二值图像的操作,因此在进行这些操作之前,通常需要先将图像转换为灰度图,并可能需要进行阈值化处理。
结构元素的选择和迭代次数应该根据具体的应用场景来调整,以达到最佳效果。

运行结果4

综合实验代码5

// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include "pch.h"
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
Mat src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
void Erosion(int, void*);
void Dilation(int, void*);
//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库
int main(int argc, char** argv)
{src = imread("93.jpeg",IMREAD_COLOR);if (src.empty()){cout << "Could not open or find the image!\n" << endl;return -1;}namedWindow("Erosion Demo", WINDOW_NORMAL);namedWindow("Dilation Demo", WINDOW_NORMAL);moveWindow("Dilation Demo", src.cols, 0);createTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",&erosion_elem, max_elem,Erosion);createTrackbar("Kernel size:\n 2n +1", "Erosion Demo",&erosion_size, max_kernel_size,Erosion);createTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",&dilation_elem, max_elem,Dilation);createTrackbar("Kernel size:\n 2n +1", "Dilation Demo",&dilation_size, max_kernel_size,Dilation);Erosion(0, 0);Dilation(0, 0);waitKey(0);return 0;
}
void Erosion(int, void*)
{int erosion_type = 0;if (erosion_elem == 0) { erosion_type = MORPH_RECT; }else if (erosion_elem == 1) { erosion_type = MORPH_CROSS; }else if (erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }Mat element = getStructuringElement(erosion_type,Size(2 * erosion_size + 1, 2 * erosion_size + 1),Point(erosion_size, erosion_size));erode(src, erosion_dst, element);imshow("Erosion Demo", erosion_dst);
}
void Dilation(int, void*)
{int dilation_type = 0;if (dilation_elem == 0) { dilation_type = MORPH_RECT; }else if (dilation_elem == 1) { dilation_type = MORPH_CROSS; }else if (dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }Mat element = getStructuringElement(dilation_type,Size(2 * dilation_size + 1, 2 * dilation_size + 1),Point(dilation_size, dilation_size));dilate(src, dilation_dst, element);imshow("Dilation Demo", dilation_dst);
}

运行结果5

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

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

相关文章

【有啥问啥】OpenAI o1的思考之前训练扩展定律、后训练扩展定律与推理扩展定律:原理与应用详解

OpenAI o1的思考之前训练扩展定律、后训练扩展定律与推理扩展定律&#xff1a;原理与应用详解 随着深度学习技术的不断发展&#xff0c;模型的规模和复杂度也迅速提升。研究人员发现了模型训练和推理过程中性能变化的规律&#xff0c;这些规律为我们提供了优化模型设计与训练的…

BGP 路由反射器

转载&#xff1a;BGP 路由反射器 / 实验介绍: / 原理概述 缺省情况下&#xff0c;路由器从它的一个 IBGP 对等体那里接收到的路由条目不会被该路由器再传递给其他IBGP对等体&#xff0c;这个原则称为BGP水平分割 原则&#xff0c;该原则的根本作用是防止 AS 内部的 BGP 路由…

linux入门——“linux基本指令”下

1.mv指令 mv指令用于移动文件或者目录。语法是mv 源文件 目标文件。它的用法需要注意&#xff1a; 当目标文件不存在的时候&#xff0c;默认是将源文件进行重命名操作&#xff0c;名字就是目标文件的名字&#xff0c;当目标文件存在的时候才会把源文件移动到目标文件。 目标文…

微服务远程调用(nacos及OpenFeign简单使用)

问题&#xff1a;在微服务中&#xff0c;每个项目是隔离开的&#xff0c;当有一个项目请求其他项目中的数据时&#xff0c;必须发起网络请求&#xff0c;本文即对此问题展开讨论。 1.使用restTemplate发送请求 //发送请求ResponseEntity<List<ItemDTO>> response …

Microsoft 365 Copilot: Wave 2 发布,开启AI时代下的全新工作流

本周一&#xff08;9月16日&#xff09;&#xff0c;微软对 Microsoft 365 Copilot 办公辅助工具进行了重大升级&#xff0c;推出 Wave 2 版本。新版 Copilot 将为 Microsoft 365 用户带来一系列新功能和改进&#xff0c;进一步提升工作效率与用户体验&#xff0c;正式开启AI时…

【machine learning-13-线性回归的向量化】

向量化 向量化简洁并行计算 向量化 线性回归的向量化表示如下&#xff0c;其中w 和 x 都分别加了箭头表示这是个向量&#xff0c;后续不加也可以表示为向量&#xff0c;w和x点乘加上b&#xff0c;就构成了多元线性回归的表达方式&#xff0c;如下&#xff1a; 那么究竟为什么…

uniapp|微信小程序 实现输入四位数 空格隔开

<template><page-meta :page-style"cssVar"></page-meta><view class"container"><u-navbartitle"优惠券兑换"placeholderbgColor"#fff":autoBack"true":titleStyle"{fontFamily: SourceHa…

navicat无法连接远程mysql数据库1130报错的解决方法

出现报错&#xff1a;1130 - Host ipaddress is not allowed to connect to this MySQL serve navicat&#xff0c;当前ip不允许连接到这个MySQL服务 解决当前ip无法连接远程mysql的方法 1. 查看mysql端口&#xff0c;并在服务器安全组中放开相应入方向端口后重启服务器 sud…

MySQL篇(存储引擎 - InnoDB存储引擎架构)(持续更新迭代)

目录 一、逻辑存储结构 1. 表空间 2. 段 3. 区 4. 页 5. 行 二、架构 1. 简介 2. 内存结构&#xff08;四部分&#xff09; Buffer Pool Change Buffer Adaptive Hash Index Log Buffer 3. 磁盘结构&#xff08;七部分&#xff09; System Tablespace File-Per-…

【工具变量】科技金融试点城市DID数据集(2000-2023年)

时间跨度&#xff1a;2000-2023年数据范围&#xff1a;286个地级市包含指标&#xff1a; year city treat post DID&#xff08;treat*post&#xff09; 样例数据&#xff1a; 包含内容&#xff1a; 全部内容下载链接&#xff1a; 参考文献-pdf格式&#xff1a;https://…

大觅网之环境部署(Environment Deployment of Da Mi Network)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

World of Warcraft [CLASSIC] International translation bug

internationalization i18n_getinternationalizationjs-CSDN博客 1&#xff09;国际化翻译不完整 Chance on melee and ranged critical strike to increase your attack power by 1262 for 10s. 2&#xff09;更新美酒节&#xff0c;服务器并发太高&#xff0c;被提出副本 Wo…

[Redis][String][下]详细讲解

目录 1.其他命令1.APPEND2.GETRANGE3.SETRANGE4.STRLEN 2.内部编码3.典型使用场景1.缓存(Cache)功能2.计数(Counter)功能3.共享会话(Session) 1.其他命令 1.APPEND 功能&#xff1a; 如果key已经存在并且是⼀个string&#xff0c;命令会将value追加到原有string的后边如果key…

第二十节:学习Redis缓存数据库实现增删改查(自学Spring boot 3.x的第五天)

这节记录下如何使用redis缓存数据库。 第一步&#xff1a; 先在服务器端安装redis&#xff0c; 下载地址&#xff1a;Releases tporadowski/redis GitHub。 第二步&#xff1a; 安装redis客户端可视化管理软件redisDesktopmanager Redis Desktop Manager - Download 第…

11. DPO 微调示例:根据人类偏好优化LLM大语言模型

在部署大模型之后&#xff0c;我们必然要和微调打交道。现在大模型的微调有非常多的方法&#xff0c;过去的文章中提到的微调方法通常依赖于问题和答案对&#xff0c;标注成本较高。 2023 年所提出的 Direct Preference Optimization&#xff08;DPO&#xff09;为我们提供了一…

C++——map和set的使用以及map系列

目录 map和set的使用 1. 序列式容器和关联式容器 2. set系列的使⽤ 2.1 set和multiset参考⽂档 2.2 set类的介绍 2.3 set的构造和迭代器 2.4 set的增删查 set的增删查关注以下⼏个接⼝即可&#xff1a; 2.6 find和erase使⽤样例&#xff1a; lower_bound(); upper_bo…

Python 从入门到实战23(属性property)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了类的定义、使用方法的相关知识。今天我们将学…

uboot:源码分析-启动第一阶段-start.S解析

start.S引入 进入start.S文件中&#xff0c;发现57行中就是_start标号的定义处 SourceInsight中添加行号 在SI中&#xff0c;如果我们知道我们要找的文件的名字&#xff0c;但是我们又不知道他在哪个目录下&#xff0c;我们要怎样找到并打开这个文件&#xff1f;方法是在SI中先…

教你快速制作一本3D翻页电子杂志

​在制作3D翻页电子杂志之前&#xff0c;我们需要了解一些基本概念。3D翻页电子杂志主要通过翻页效果来展示内容&#xff0c;读者可以通过手指滑动或点击鼠标来进行翻页。此外&#xff0c;它还支持图片、文字、视频等多种媒体形式的展示&#xff0c;为读者带来全方位的阅读体验…

KTH5774 —— 3D 摇杆/操纵杆霍尔位置传感器芯片

KTH5774 是一款摇杆、操纵杆专用的 3D 霍尔磁感 应芯片&#xff0c;主要面向对线性度和可靠性要求严格的应用 场景。 KTH5774 基于 3D 霍尔技术&#xff0c;内部分别集成了 X 轴、 Y 轴和 Z 轴三个独立的霍尔元件&#xff0c;能够通过测量和 处理磁通密度矢量的三个空间分量…