OpenCV学习(10) 图像的腐蚀与膨胀(1)
建议大家看看网络视频教程: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)的更多相关文章
- OpenCV学习笔记——图像的腐蚀与膨胀
顺便又复习了一下cvcopy如何进行图像拼接(最近觉得打开多幅图像分别看不如缩小掉放拼接到一幅图像上对比来的好) 首先把拼接的目标图像设置兴趣区域ROI,比如我有一个total,要把a.b.c分别从左 ...
- OpenCV学习(11) 图像的腐蚀与膨胀(2)
先对一副灰度图像进行腐蚀操作,然后在腐蚀后的图像上再进行膨胀操作,我们定义这个操作为开操作. 先对一副图像进行膨胀操作,然后在膨胀后的图像上再进行腐蚀操作,我们定义这个操作为闭操作. 开操 ...
- OpenCV学习(12) 图像的腐蚀与膨胀(3)
通过使用不同的结构元素来进行膨胀腐蚀操作,可以检测图像中的角点,下面就一步一步看这个算法如果实现角点检测. 原图像: 首先我们创建四个结构元素 先用十字结构元素对原图像进行膨胀操作,得到下面的图像 再 ...
- opencv:图像的腐蚀和膨胀
1.图像的腐蚀 图像的腐蚀和膨胀都是相对于像素值高(白色方向)说的,腐蚀简单的说就是白色”被腐蚀“了,也就是像素值低(黑色方向)的变多,白色变少. 腐蚀的原理是利用一个内核对图像进行卷积(扫描),内核 ...
- c#数字图像处理(十二)图像的腐蚀与膨胀
背景知识 腐蚀与膨胀基本原理:就是用一个特定的结构元素来与待处理图像按像素做逻辑操作:可以理解成拿一个带孔的网格板(结构元素矩阵中元素为1的为孔)盖住图像的某一部分,然后按照各种不同的观察方式来确定操 ...
- opencv中的图像形态学——腐蚀膨胀
腐蚀膨胀是图像形态学比较常见的处理,腐蚀一般可以用来消除噪点,分割出独立的图像元素等. 一般腐蚀操作对二值图进行处理,腐蚀操作如下图,中心位置的像素点是否与周围领域的像素点颜色一样(即是否是白色点,即 ...
- opencv学习(六)——图像基本操作
图像基本操作 一.访问和修改像素值 先来理解一下,图像与一般的矩阵或张量有何不同(不考虑图像的格式,元数据等信息).首先,一张图像有自己的属性,宽,高,通道数.其中宽和高是我们肉眼可见的属性,而通道数 ...
- opencv学习笔记-图像对比度、亮度调节
在数学中我们学过线性理论,在图像亮度和对比度调节中同样适用,看下面这个公式: 在图像像素中其中: 参数f(x)表示源图像像素. 参数g(x) 表示输出图像像素. 参数a(需要满足a>0)被称为增 ...
- opencv学习笔记-图像叠加、混合
在图像处理中,目标区域定义为感兴趣区域ROI(region of Interest),这是后期图像处理的基础,在获取ROI后,进行一些列的处理.ROI区域在Opencv中就是Rect,先构建Rect, ...
随机推荐
- day2 购物商城
购物商城 商品展示.价格 买,加入购物车 付款,钱不够.(减商品,充值)
- 微信小程序之wepy自动化架构搭建(fly+wepy-plugin-replace)
前言 本文章秉着自动化工程项目的思想搭建的,基础架子完全按照wepy官网搭建,在基础上增加配置达到自动化项目.新增动flxio拦截器自动处理接口,新增根据环境变量来改变运行时的参数. Fly.js 小 ...
- 免费的.NET混淆和反编译工具
免费的.NET代码混淆工具: Eazfuscator.NET http://www.foss.kharkov.ua/g1/projects/eazfuscator/dotnet/Default.as ...
- Redis实战(一)
一.准备 Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库.Redis的出现,很大程度补偿了memcached这类key/valu ...
- saltstack系统初始化(九)
一.系统初始化需要的配置 当我们的服务器上架并安装好操作系统后,都会有一些基础的操作,所以生产环境中使用SaltStack,建议将所有服务器都会涉及的基础配置或者软件部署归类放在base环境下.此处, ...
- c# 递归异步获取本地驱动器下所有文件
//获取所有驱动器 string[] drives = Environment.GetLogicalDrives(); foreach (string driver in drives) { Cons ...
- 转:使用python的Flask实现一个RESTful API服务器端
提示:可以学习一下flask框架中对于密码进行校验的部分.封装了太多操作. 最近这些年,REST已经成为web services和APIs的标准架构,很多APP的架构基本上是使用RESTful的形式了 ...
- 深度学习应用系列(四)| 使用 TFLite Android构建自己的图像识别App
深度学习要想落地实践,一个少不了的路径即是朝着智能终端.嵌入式设备等方向发展.但终端设备没有GPU服务器那样的强大性能,那如何使得终端设备应用上深度学习呢? 所幸谷歌已经推出了TFMobile,去年又 ...
- cogs——2478. [HZOI 2016]简单的最近公共祖先
2478. [HZOI 2016]简单的最近公共祖先 ★☆ 输入文件:easy_LCA.in 输出文件:easy_LCA.out 简单对比时间限制:2 s 内存限制:128 MB [题 ...
- 【BZOJ 1969】 1969: [Ahoi2005]LANE 航线规划 (树链剖分+线段树)
1969: [Ahoi2005]LANE 航线规划 Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星 ...