1. 膨胀与腐蚀的原理

膨胀与腐蚀是数学形态学在图像处理中最基础的操作。在笔者之前的文章《图像的卷积(滤波)运算(一)——图像梯度》《图像的卷积(滤波)运算(二)——高斯滤波》具体介绍了图像卷积\滤波的具体的概念与操作,图像的膨胀与腐蚀其实也是一种类似的卷积操作。其卷积操作非常简单,对于图像的每个像素,取其一定的邻域,计算最大值/最小值作为新图像对应像素位置的像素值。其中,取最大值就是膨胀,取最小值就是腐蚀。

2. 膨胀的具体实现

1) OpenCV实现

在OpenCV中实现了图像膨胀的函数dilate(),可以直接调用:

Mat img = imread(imagename, IMREAD_GRAYSCALE);
if (img.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
} //OpenCV方法
Mat dilated_cv;
dilate(img, dilated_cv, Mat());

dilate()函数第一个参数表示输入影像,第二个参数表示输出影像,第三个表示一个默认的核,在3X3的范围内寻找最大值。

2) C/C++实现

在一般的图像处理时,图像读写是由专门的组件进行读取的。这这里仍然使用OpenCV进行读取,以免增加复杂性。而在CV::Mat类中,提供了at()函数访问某一行某一列的像素值,可以通过at()函数去访问每一个像素的领域。

与之前OpenCV实现的一样,对于每一个像素,遍历以其像素位置为中心的3X3邻域,取最大值作为新图像对应位置的像素值。

其具体实现如下:

//从文件中读取成灰度图像
const char* imagename = "D:\\Data\\imgDemo\\lena.jpg";
Mat img = imread(imagename, IMREAD_GRAYSCALE);
if (img.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
} //自定义方法
Mat dilated_my;
dilated_my.create(img.rows, img.cols, CV_8UC1);
for (int i = 0; i < img.rows; ++i)
{
for (int j = 0; j < img.cols; ++j)
{
//uchar minV = 255;
uchar maxV = 0; //遍历周围最大像素值
for (int yi = i-1; yi <= i+1; yi++)
{
for (int xi = j-1; xi <= j+1; xi++)
{
if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
{
continue;
}
//minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
}
}
dilated_my.at<uchar>(i, j) = maxV;
}
}

3) 验证与结果

为了验证自己的算法是否正确,可以通过把两者膨胀的结果通过compare()函数进行比较。compare()函数会逐个比较两者的像素值,如果相同就会返回255(白色),如果不相同就会返回0(黑色)。整个过程的具体实现如下:

#include <iostream>
#include <algorithm>
#include <opencv2\opencv.hpp> using namespace cv;
using namespace std; int main()
{
//从文件中读取成灰度图像
const char* imagename = "D:\\Data\\imgDemo\\lena.jpg";
Mat img = imread(imagename, IMREAD_GRAYSCALE);
if (img.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
} //OpenCV方法
Mat dilated_cv;
dilate(img, dilated_cv, Mat()); //自定义方法
Mat dilated_my;
dilated_my.create(img.rows, img.cols, CV_8UC1);
for (int i = 0; i < img.rows; ++i)
{
for (int j = 0; j < img.cols; ++j)
{
//uchar minV = 255;
uchar maxV = 0; //遍历周围最大像素值
for (int yi = i-1; yi <= i+1; yi++)
{
for (int xi = j-1; xi <= j+1; xi++)
{
if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
{
continue;
}
//minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
}
}
dilated_my.at<uchar>(i, j) = maxV;
}
} //比较两者的结果
Mat c;
compare(dilated_cv, dilated_my, c, CMP_EQ); //显示
imshow("原始", img);
imshow("膨胀_cv", dilated_cv);
imshow("膨胀_my", dilated_my);
imshow("比较结果", c); waitKey(); return 0;
}

其运行结果如下所示。可以发现最后的比较结果是一张白色的图像,说明自己实现的算法是正确的。

3. 腐蚀的具体实现

同样的办法可以实现图像腐蚀的过程,只要将求局部最大值改成局部最小值就可以了。具体实现过程如下:

#include <iostream>
#include <algorithm>
#include <opencv2\opencv.hpp> using namespace cv;
using namespace std; int main()
{
//从文件中读取成灰度图像
const char* imagename = "D:\\Data\\imgDemo\\lena.jpg";
Mat img = imread(imagename, IMREAD_GRAYSCALE);
if (img.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
} //OpenCV方法
Mat eroded_cv;
erode(img, eroded_cv, Mat()); //自定义方法
Mat eroded_my;
eroded_my.create(img.cols, img.rows, CV_8UC1);
for (int i = 0; i < img.rows; ++i)
{
for (int j = 0; j < img.cols; ++j)
{
uchar minV = 255;
//uchar maxV = 0; //遍历周围最大像素值
for (int yi = i-1; yi <= i+1; yi++)
{
for (int xi = j-1; xi <= j+1; xi++)
{
if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
{
continue;
}
minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
//maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
}
}
eroded_my.at<uchar>(i, j) = minV;
}
} //比较两者的结果
Mat c;
compare(eroded_cv, eroded_my, c, CMP_EQ); //显示
imshow("原始", img);
imshow("膨胀_cv", eroded_cv);
imshow("膨胀_my", eroded_my);
imshow("比较结果", c); waitKey(); return 0;
}

其运行结果如下:

图像的膨胀与腐蚀——OpenCV与C++的具体实现的更多相关文章

  1. Atitit 图像处理—图像形态学(膨胀与腐蚀)

    Atitit 图像处理-图像形态学(膨胀与腐蚀) 1.1. 膨胀与腐蚀1 1.2. 图像处理之二值膨胀及应用2 1.3. 测试原理,可以给一个5*5pic,测试膨胀算法5 1.4. Photoshop ...

  2. 膨胀和腐蚀 - cvErode() 和 cvDilate() 函数实现

    前言 膨胀就是对图中的每个像素取其核范围内最大的那个值,腐蚀就相反.这两个操作常用来突出显示图的某个高亮部分或者昏暗部分以及去噪.本文展示两个分别对图像进行膨胀和腐蚀的例子. 膨胀和腐蚀函数 cvEr ...

  3. OpenCV膨胀与腐蚀

    膨胀与腐蚀 本篇博客主要介绍使用OpenCV中的函数接口实现对一个图片的腐蚀或者膨胀,听起来有点像是对图像进行放大和缩小的意思,如果你也是这样认为,那我只能说你跟我一样肤浅!!在OpenCV中几乎所有 ...

  4. opencv之膨胀与腐蚀

    腐蚀和膨胀 Erosion/Dilation erosion/dilation,用白话说,就是让图像亮的区域收缩和扩张. 原理 我们定义一个卷积核矩阵.这个矩阵可以是任何形状的,但通常而言,是矩形或者 ...

  5. OpenCV——图像处理入门:膨胀与腐蚀、图像模糊、边缘检测

    全部外部依赖项: opencv_aruco341d.lib opencv_bgsegm341d.lib opencv_calib3d341d.lib opencv_bioinspired341d.li ...

  6. OpenCV膨胀和腐蚀示例代码

    #include<cv.h> #include<highgui.h> int main(int argc, char** argv) { IplImage* img = cvL ...

  7. 学习 opencv---(9)形态学图像处理(一):膨胀和腐蚀

    本篇文章中,我们一起探究了图像处理中,最基本的形态学运算--膨胀与腐蚀.浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试.......... 一.理论 ...

  8. paper 76:膨胀、腐蚀、开、闭运算——数字图像处理中的形态学

    膨胀.腐蚀.开.闭运算是数学形态学最基本的变换.本文主要针对二值图像的形态学膨胀:把二值图像各1像素连接成分的边界扩大一层(填充边缘或0像素内部的孔):腐蚀:把二值图像各1像素连接成分的边界点去掉从而 ...

  9. 膨胀、腐蚀、开、闭(matlab实现)

    膨胀.腐蚀.开.闭运算是数学形态学最基本的变换. 本文主要针对二值图像的形态学 膨胀:把二值图像各1像素连接成分的边界扩大一层(填充边缘或0像素内部的孔): B=[0 1 0      1 1 1   ...

随机推荐

  1. Java的自定义注解使用实例

    概念 Java有五个元注解,自动继承java.lang.annotation.Annotation. 什么是元注解,可以理解为其他普通注解进行解释说明 @Target  该注解的使用范围,限定应用场景 ...

  2. go语言调度器源代码情景分析之一:开篇语

    专题简介 本专题以精心设计的情景为线索,结合go语言最新1.12版源代码深入细致的分析了goroutine调度器实现原理. 适宜读者 go语言开发人员 对线程调度器工作原理感兴趣的工程师 对计算机底层 ...

  3. 【Python3爬虫】用Python中的队列来写爬虫

    一.写在前面 当你看着你的博客的阅读量慢慢增加的时候,内心不禁有了些小激动,但是不得不吐槽一下--博客园并不会显示你的博客的总阅读量是多少.而这一篇博客就将教你怎么利用队列这种结构来编写爬虫,最终获取 ...

  4. Python调用ansible API系列(一)获取资产信息

    你想让ansible工作首先就需要设置资产信息,那么我们如何通过使用Python调取Ansible的API来获取资产信息呢? 要提前准备一个hosts文件 获取组或者主机 #!/usr/bin/env ...

  5. 已实现乐观锁功能,FreeSql.DbContext 准备起航

    上回说到 FreeSql.DbContext 的规则,以及演示它的执行过程,可惜当时还不支持"乐观锁",对于更新数据来讲并不安全. FreeSql 核心库 v0.3.27 已提供乐 ...

  6. 搜狗输入法与VS快捷键有冲突_处理办法

    前言:搜狗输入法是大家常用的文字输入工具,但是在开启输入法的时候,VS的一些快捷键无法正常使用,如智能提示快捷键:Ctrl+.,这就非常尴尬了,除非把输入法切换成英文或者卸载搜狗改别的输入法,一个是切 ...

  7. Android WebView 缓存

    android很多情况是使用webView用来显示界面,但是webview的加载速度略慢,想让这个webview更快一些所以需要使用缓存,在没有更新的时候使用缓存技术来提高速度.总体来讲有两个方案可以 ...

  8. 持续集成之 Nuget 进阶

    持续集成之 Nuget 进阶 Intro 之前介绍了一篇基于 Azure pipeline 的 nuget 包的持续集成配置,但是比较粗糙,这里介绍一下结合 Cake 实现更优雅的 nuget 包发布 ...

  9. ==运算符和equals()方法的区别

    Java语言程序中判断两个变量是否相等有两种方式:一是运用==运算符,二是运用equals方法. 1. ==运算符 对于==运算符来说,如果两个变量是基本类型的,并且是数值类型,则只要它们的值相等,就 ...

  10. Pytorch系列教程-使用字符级RNN对姓名进行分类

    前言 本系列教程为pytorch官网文档翻译.本文对应官网地址:https://pytorch.org/tutorials/intermediate/char_rnn_classification_t ...