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, ...
随机推荐
- 第二章:监控属性(Observables)
关于Knockout的3个重要概念(Observables,DependentObservables,ObservableArray),本人无法准确表达它的准确含义,所以暂定翻译为(监控属性.依赖监控 ...
- vscode 解决vue emmet不起作用
现在 vscode 自带的提示已经很好用了,大部分时间自带的提示展示的 emmet 内容已经是所需的了 在首选项 设置中配置 v1.15.1 之后需要这样设置: "emmet.trigger ...
- CodeForces 909E Coprocessor
题解. 贪心,拓扑排序. 和拓扑排序一样,先把$flag$为$0$的点能删的都删光,露出来的肯定都是$flag$为$0$的,然后疯狂删$flag$为$0$的,这些会使答案加$1$,反复操作就可以了. ...
- 安卓 listView 优化
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_m ...
- CodeForces 1063B. Labyrinth 性质
给定$n *m$的格子 询问从$(r, c)$开始最多向左走$x$步,向右走$y$步 询问有多少个格子可以从$(r, c)$到达 有障碍物,$n, m \leqslant 2 * 10^3$ 对于一个 ...
- [BZOJ4028][HEOI2015]公约数数列(分块)
先发掘性质: 1.xor和gcd均满足交换律与结合率. 2.前缀gcd最多只有O(log)个. 但并没有什么数据结构能同时利用这两个性质,结合Q=10000,考虑分块. 对每块记录这几个信息: 1.块 ...
- [BZOJ4539][HNOI2016]树(主席树)
4539: [Hnoi2016]树 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 746 Solved: 292[Submit][Status][D ...
- POJ 3974 Palindrome 字符串 Manacher算法
http://poj.org/problem?id=3974 模板题,Manacher算法主要利用了已匹配回文串的对称性,对前面已匹配的回文串进行利用,使时间复杂度从O(n^2)变为O(n). htt ...
- Codeforces Round #478 (Div. 2) ABCDE
A. Aramic script time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- 【欧拉函数】BZOJ4173-数学
[题目大意] [思路] 基本是popoqqq大爷的题解,稍微添加了几句自己的注释,方便理解 同理,如果n%k+m%k<k等价于0 =∑([(n+m)/k]-[n/k]-[m/k])×φ(k) … ...