OpenCV腐蚀与膨胀(Eroding and Dilating)
腐蚀与膨胀(Eroding and Dilating)
原理
Note
以下内容来自于Bradski和Kaehler的大作: Learning OpenCV .
形态学操作
简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将 结构元素 作用于输入图像来产生输出图像。
最基本的形态学操作有二:腐蚀与膨胀(Erosion 与 Dilation)。 他们的运用广泛:
- 消除噪声
- 分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
- 寻找图像中的明显的极大值区域或极小值区域。
通过以下图像,我们简要来讨论一下膨胀与腐蚀操作(译者注:注意这张图像中的字母为黑色,背景为白色,而不是一般意义的背景为黑色,前景为白色):

膨胀
此操作将图像
与任意形状的内核 (
),通常为正方形或圆形,进行卷积。内核
有一个可定义的 锚点, 通常定义为内核中心点。进行膨胀操作时,将内核
划过图像,将内核
覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:
背景(白色)膨胀,而黑色字母缩小了。
腐蚀
腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。
进行腐蚀操作时,将内核
划过图像,将内核
覆盖区域的最小相素值提取,并代替锚点位置的相素。以与膨胀相同的图像作为样本,我们使用腐蚀操作。从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。

源码
下面是本教程的源码, 你也可以从 here 下载。
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h> using namespace cv; /// 全局变量
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; /** Function Headers */
void Erosion( int, void* );
void Dilation( int, void* ); /** @function main */
int main( int argc, char** argv )
{
/// Load 图像
src = imread( argv[1] ); if( !src.data )
{ return -1; } /// 创建显示窗口
namedWindow( "Erosion Demo", CV_WINDOW_AUTOSIZE );
namedWindow( "Dilation Demo", CV_WINDOW_AUTOSIZE );
cvMoveWindow( "Dilation Demo", src.cols, 0 ); /// 创建腐蚀 Trackbar
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 ); /// 创建膨胀 Trackbar
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 ); /// Default start
Erosion( 0, 0 );
Dilation( 0, 0 ); waitKey(0);
return 0;
} /** @function Erosion */
void Erosion( int, void* )
{
int erosion_type;
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 );
} /** @function Dilation */
void Dilation( int, void* )
{
int dilation_type;
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 );
}
解释
大部分代码应该不需要解释了 (如果有任何疑问,请回头参考前面的教程)。 让我们来回顾一下本程序的总体流程:
- 装载图像 (可以是 RGB图像或者灰度图 )
- 创建两个显示窗口 (一个用于膨胀输出,一个用于腐蚀输出)
- 为每个操作创建两个 Trackbars:
- 第一个 trackbar “Element” 返回 erosion_elem 或者 dilation_elem
- 第二个 trackbar “Kernel size” 返回 erosion_size 或者 dilation_size 。
- 每次移动标尺, 用户函数 Erosion 或者 Dilation 就会被调用,函数将根据当前的trackbar位置更新输出图像。
让我们分析一下这两个函数:
Erosion:
/** @function Erosion */
void Erosion( int, void* )
{
int erosion_type;
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 );
}进行 腐蚀 操作的函数是 erode 。 它接受了三个参数:
src: 原图像
erosion_dst: 输出图像
element: 腐蚀操作的内核。 如果不指定,默认为一个简单的
矩阵。否则,我们就要明确指定它的形状,可以使用函数getStructuringElement:Mat element = getStructuringElement( erosion_type,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
我们可以为我们的内核选择三种形状之一:
- 矩形: MORPH_RECT
- 交叉形: MORPH_CROSS
- 椭圆形: MORPH_ELLIPSE
然后,我们还需要指定内核大小,以及 锚点 位置。不指定锚点位置,则默认锚点在内核中心位置。
就这些了,我们现在可以对图像进行腐蚀操作了。
Note
OpenCV的 erode 函数还有另外的参数,其中一个参数允许你一下对图像进行多次腐蚀操作。在这个简单的文档中没有用到它,但是你可以参考OpenCV的使用手册。
Dilation:
下面是膨胀的代码,你可以看到,它和 Erosion 函数是多么相似。 这里我们同样可以指定内核的形状,锚点和大小。
/** @function Dilation */
void Dilation( int, void* )
{
int dilation_type;
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 );
}
结果
编译并使用图像路径作为参数运行程序,比如我们使用以下图像:

下面是操作的结果。 更改Trackbars的位置就会产生不一样的输出图像,自己试试吧。 最后,你还可以通过增加第三个Trackbar来控制膨胀或腐蚀的次数。

翻译者
niesu@ OpenCV中文网站 <sisongasg@hotmail.com>
from: http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html#morphology-1
OpenCV腐蚀与膨胀(Eroding and Dilating)的更多相关文章
- OpenCV 腐蚀与膨胀(Eroding and Dilating)
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #i ...
- OpenCV学习笔记(六) 滤波器 形态学操作(腐蚀、膨胀等)
转自:OpenCV 教程 另附:计算机视觉:算法与应用(2012),Learning OpenCV(2009) 平滑图像:滤波器 平滑 也称 模糊, 是一项简单且使用频率很高的图像处理方法.平滑处理的 ...
- OpenCV图像处理篇之腐蚀与膨胀
转载请注明出处:http://xiahouzuoxin.github.io/notes 腐蚀与膨胀 腐蚀和膨胀是图像的形态学处理中最主要的操作,之后遇见的开操作和闭操作都是腐蚀和膨胀操作的结合运算. ...
- OpenCV学习(10) 图像的腐蚀与膨胀(1)
建议大家看看网络视频教程:http://www.opencvchina.com/thread-886-1-1.html 腐蚀与膨胀都是针对灰度图的形态学操作,比如下面的一副16*16的灰度图. ...
- opencv 4 图像处理(2 形态学滤波:腐蚀与膨胀,开运算、闭运算、形态学梯度、顶帽、黑帽)
腐蚀与膨胀 膨胀(求局部最大值)(dilate函数) #include <opencv2/core/core.hpp> #include <opencv2/highgui/highg ...
- OpenCV学习笔记——图像的腐蚀与膨胀
顺便又复习了一下cvcopy如何进行图像拼接(最近觉得打开多幅图像分别看不如缩小掉放拼接到一幅图像上对比来的好) 首先把拼接的目标图像设置兴趣区域ROI,比如我有一个total,要把a.b.c分别从左 ...
- OpenCV(6)-腐蚀和膨胀
腐蚀和膨胀属于形态学操作. 腐蚀和膨胀 腐蚀是指:将卷积核B滑过图像A,找出卷积核区域内最小像素值作为锚点像素值.这一操作可以扩大低像素值区域. 膨胀是指:将卷积核B滑过图像A,找出卷积核区域内最大像 ...
- OpenCV学习 7:图像形态学:腐蚀、膨胀
原创文章,欢迎转载,转载请注明出处 首先什么是图像形态学?额,这个抄下百度到的答案.基本思想: 用具有一定形态的结构元素去度量和提取图像中的对应形状已达到对图像分析和识别的目的,形态学图像处理表 ...
- Java基于opencv实现图像数字识别(五)—腐蚀、膨胀处理
腐蚀:去除图像表面像素,将图像逐步缩小,以达到消去点状图像的效果:作用就是将图像边缘的毛刺剔除掉 膨胀:将图像表面不断扩散以达到去除小孔的效果:作用就是将目标的边缘或者是内部的坑填掉 使用相同次数的腐 ...
随机推荐
- Http请求加签、验证操作
加签.验签的作用 常见的http请求交互过程中,请求参数通过url或者request body等形式传输.但是由于http请求的开放性,使得请求参数很容易被拦截篡改.因此,需要对请求参数进行加签,然后 ...
- LeetCode239. Sliding Window Maximum
Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...
- AC日记——色板游戏 洛谷 P1558
色板游戏 思路: sb题: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 struct Tre ...
- 三十八 ThreadLocal
在多线程环境下,每个线程都有自己的数据.一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程,而全局变量的修改必须加锁. 但是局部变量也有问题,就是在函数调用的 ...
- win 10 下面安装 mysql-8.0.12-winx64 的过程
win 10 下面安装 mysql-8.0.12-winx64 的过程 1.官网下载 mysql 2.解压到你要安装的目录 3.在mysql目录D:\Programming\mysql-8.0.12- ...
- 图片乱码问题 解决方法 php
两个开发者都是下载同一个项目的git代码,但到本地环境,一个可以正常显示图片验证码,一个不行,找个半天开始以为环境问题 找了半天 不是 很多没说到重点 其实不只是当前文件格式问题 也要考虑其他调用文件 ...
- 深入解析php中的foreach问题
本篇文章是对php中的foreach问题进行了详细的分析介绍,需要的朋友参考下 前言:php4中引入了foreach结构,这是一种遍历数组的简单方式.相比传统的for循环,foreach能够更加便 ...
- vmware漏洞之四:简评USE-AFTER-SILENCE: EXPLOITING A QUIETLY PATCHED UAF IN VMWARE
转:https://www.zerodayinitiative.com/blog/2017/6/26/use-after-silence-exploiting-a-quietly-patched-ua ...
- LoggerAspect
package nc.oss.utils; import java.util.Date; import nc.bs.framework.common.InvocationInfoProxy; impo ...
- Eclipse有助于提高开发速度的快捷键
用Eclipse已经很长一段时间了,自己常用的几个快捷键也已经很熟,但还是有一些自己不经常在开发中使用,但非常使用的快捷键,记录下来,以后利用来提高开发效率. 1.ctrl + shift + r ...