建议大家看看网络视频教程:http://www.opencvchina.com/thread-886-1-1.html 

 

腐蚀与膨胀都是针对灰度图的形态学操作,比如下面的一副16*16的灰度图。

它每个像素对应的值为(每个像素值范围都在0-255之间)为:

      我们定义一个5*5的结构元素,该结构元素用5*5的矩阵表示,其中为1的单元,表示该单元在结构元素中有效,另外还定义一个锚点,坐标为(2,2),在单元格中用蓝色表示。

腐蚀/膨胀的操作就是用结构元素的锚点位置对齐图像的像素,然后从左上角的第一个像素滑动到右下角的最后一个像素。

在滑动到每个像素时,结构元素中为1的各个坐标格子会与相应的像素对齐。比如滑动到第一个像素时,如下图所示:

此时,原图像中对齐的格子,如下图所示。

       腐蚀操作就是取其中的最小值,代替原素像素值,即image(0,0)的像素值为min(0,1,2,16,32)=0,而膨胀操作则相反,是取最大值代替原像素,即image(0,0)=max(0,1,2,16,32)=32。

下面我们再看一个例子,当结构元素滑动到image(4,4 ) 位置时候,图像的腐蚀膨胀操作:

      此时,结构元素对齐的像素如下图所示,对于腐蚀操作,此时image(4,4)应该等于min(36,52,66,67,68,69,70,84,100)=36,而膨胀操作,则是image(4,4)等于max(36,52,66,67,68,69,70,84,100)=100。

需要注意下面的一种情况:

结构元素如下图所示,仍是5*5的十字形状,但锚点位置在(3,3),此时当结构元素在图像中滑动时候,会有一些特殊情况需要注意。

比如滑动到图像的(0,0)位置时,结构元素中为1的单元格和图像没有交叉的格子,此时按我的理解,应该保持像素的值不变,但opencv中却不是这样,当腐蚀时,此时(0,0)位置像素值为255,当膨胀时,(0,0)位置像素值为0。

下面是我写的简单的腐蚀膨胀函数代码:

cv::Mat gMophEx::Erode(cv::Mat& img,  cv::Mat  kernel, cv::Point anchor)
{
cv::Mat tmpImg;
img.copyTo(tmpImg);
int i, j, m, n;
uchar* p;
for(i=0; i<img.rows; i++)
{
p = tmpImg.ptr<uchar>(i);
for(j=0; j<img.cols; j++)
{
int min = 100000;
for(m = 0; m < kernel.rows; m++)
{
for(n=0; n <kernel.cols; n++)
{
if(kernel.data[m*kernel.cols+n]==1)
{
//printf("i=%d, j=%d, m=%d,n=%d,tt1=%d, tt2=%d, tt3=%d\n",i,j,m,n,j+n-anchor.y,i + m - anchor.x,(i + m - anchor.x)*img.cols + j+n-anchor.y);
if(j+n-anchor.x < 0 || j+n-anchor.y >=img.cols || i + m - anchor.x < 0 || i + m - anchor.x >= img.rows)
continue;
//printf("%d \n",img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]);
if(img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]<min)
min = img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y];
}
}
} if (min < 256)
{
p[j] = min;
}
else if(min==100000)
{
p[j] = 255; //opencv结果是这样,当腐蚀时候,当前像素找不到相应的点,赋予最大值
} }
}
return tmpImg;
} cv::Mat gMophEx::Dilate(cv::Mat& img, cv::Mat kernel, cv::Point anchor)
{
cv::Mat tmpImg;
img.copyTo(tmpImg);
int i, j, m, n;
uchar* p;
for(i=0; i<img.rows; i++)
{
p = tmpImg.ptr<uchar>(i);
for(j=0; j<img.cols; j++)
{
int max=-1;
for(m = 0; m < kernel.rows; m++)
{
for(n=0; n <kernel.cols; n++)
{
if(kernel.data[m*kernel.cols+n]==1)
{
//printf("i=%d, j=%d, m=%d,n=%d, tt=%d\n",i,j,m,n,(i + m - anchor.x)*img.cols + j+n-anchor.y);
if(j+n-anchor.y < 0 || j+n-anchor.y >=img.cols || i + m - anchor.x < 0 || i + m - anchor.x >= img.rows)
continue;
//printf("%d \n",img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]);
if(img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]>max)
max = img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y];
}
}
} if (max >= 0)
{
p[j] = max;
}
else if(max == -1)
{
p[j] = 0;
}
//PrintMat(tmpImg);
}
}
return tmpImg;
}

最后我们对图像进行腐蚀操作,得到新的图像像素值为:

膨胀操作后的像素值为:

程序代码: 工程FirstOpenCV4

OpenCV学习(10) 图像的腐蚀与膨胀(1)的更多相关文章

  1. OpenCV学习笔记——图像的腐蚀与膨胀

    顺便又复习了一下cvcopy如何进行图像拼接(最近觉得打开多幅图像分别看不如缩小掉放拼接到一幅图像上对比来的好) 首先把拼接的目标图像设置兴趣区域ROI,比如我有一个total,要把a.b.c分别从左 ...

  2. OpenCV学习(11) 图像的腐蚀与膨胀(2)

    先对一副灰度图像进行腐蚀操作,然后在腐蚀后的图像上再进行膨胀操作,我们定义这个操作为开操作. 先对一副图像进行膨胀操作,然后在膨胀后的图像上再进行腐蚀操作,我们定义这个操作为闭操作.       开操 ...

  3. OpenCV学习(12) 图像的腐蚀与膨胀(3)

    通过使用不同的结构元素来进行膨胀腐蚀操作,可以检测图像中的角点,下面就一步一步看这个算法如果实现角点检测. 原图像: 首先我们创建四个结构元素 先用十字结构元素对原图像进行膨胀操作,得到下面的图像 再 ...

  4. opencv:图像的腐蚀和膨胀

    1.图像的腐蚀 图像的腐蚀和膨胀都是相对于像素值高(白色方向)说的,腐蚀简单的说就是白色”被腐蚀“了,也就是像素值低(黑色方向)的变多,白色变少. 腐蚀的原理是利用一个内核对图像进行卷积(扫描),内核 ...

  5. c#数字图像处理(十二)图像的腐蚀与膨胀

    背景知识 腐蚀与膨胀基本原理:就是用一个特定的结构元素来与待处理图像按像素做逻辑操作:可以理解成拿一个带孔的网格板(结构元素矩阵中元素为1的为孔)盖住图像的某一部分,然后按照各种不同的观察方式来确定操 ...

  6. opencv中的图像形态学——腐蚀膨胀

    腐蚀膨胀是图像形态学比较常见的处理,腐蚀一般可以用来消除噪点,分割出独立的图像元素等. 一般腐蚀操作对二值图进行处理,腐蚀操作如下图,中心位置的像素点是否与周围领域的像素点颜色一样(即是否是白色点,即 ...

  7. opencv学习(六)——图像基本操作

    图像基本操作 一.访问和修改像素值 先来理解一下,图像与一般的矩阵或张量有何不同(不考虑图像的格式,元数据等信息).首先,一张图像有自己的属性,宽,高,通道数.其中宽和高是我们肉眼可见的属性,而通道数 ...

  8. opencv学习笔记-图像对比度、亮度调节

    在数学中我们学过线性理论,在图像亮度和对比度调节中同样适用,看下面这个公式: 在图像像素中其中: 参数f(x)表示源图像像素. 参数g(x) 表示输出图像像素. 参数a(需要满足a>0)被称为增 ...

  9. opencv学习笔记-图像叠加、混合

    在图像处理中,目标区域定义为感兴趣区域ROI(region of Interest),这是后期图像处理的基础,在获取ROI后,进行一些列的处理.ROI区域在Opencv中就是Rect,先构建Rect, ...

随机推荐

  1. java 基础知识-数组的7种算法(排序、求和、最值、遍历...)

    遍历 遍历就是把这个数组的每个元素 显示出来 遍历的方法就是先定义这个数组的大小,然后用FOR循环来完成数组,例如 double[] score = new double[5]; Scanner in ...

  2. 微信小程序之wepy自动化架构搭建(fly+wepy-plugin-replace)

    前言 本文章秉着自动化工程项目的思想搭建的,基础架子完全按照wepy官网搭建,在基础上增加配置达到自动化项目.新增动flxio拦截器自动处理接口,新增根据环境变量来改变运行时的参数. Fly.js 小 ...

  3. 【UOJ】#79. 一般图最大匹配

    题解 板子!我相信其实没人来看我的板子!但是为了防止我忘记,我还是要写点什么 我们考虑二分图,为什么二分图就能那么轻松地写出匹配的代码呢?因为匹配只会发生在黑点和白点之间,我们找寻增广路,必然是一黑一 ...

  4. Educational Codeforces Round 45 (Rated for Div. 2) F - Flow Control

    F - Flow Control 给你一个有向图,要求你给每条边设置流量,使得所有点的流量符合题目给出的要求. 思路:只有在所有点的流量和为0时有解,因为增加一条边的值不会改变所有点的总流量和, 所以 ...

  5. 使用afl-dyninst fuzz无源码的二进制程序

    转:http://ele7enxxh.com/Use-AFL-dyninst-To-Fuzz-Blackbox-Binaries.html 使用afl-dyninst fuzz无源码的二进制程序 通常 ...

  6. /.nav-tabs :是普通标签页 .nav-pills:胶囊式标签页 action ;默认的激活项,给<li>加默认显示的是哪个标签页内容 .nav是标签页的一个基类,给ul加 .nav-stacked: 垂直排列BootStrap

    <meta name="viewport" content="with=device-width, initial-scale=1, user-scalabe=no ...

  7. 网页后门工具laudanum

     网页后门工具laudanum laudanum是Kali Linux预先安装的Web Shell工具.它支持多种Web后台技术,如ASP.ASP.net .JSP.PHP.Coldfusion.它提 ...

  8. code forces 505A

    Mr. Kitayuta's Gift Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64 ...

  9. socket的使用二

    基于UDP协议的socket udp是无链接的,先启动哪一端都不会报错 简单使用 server端 import socket udp_sk = socket.socket(type=socket.SO ...

  10. 【HDU 6020】 MG loves apple (乱搞?)

    MG loves apple  Accepts: 20  Submissions: 693  Time Limit: 3000/1500 MS (Java/Others)  Memory Limit: ...