
注意
以下的理论说明内容,来自于Bradski 和Kaehler 撰写的Learning OpenCV 一书。
•.简单来说:一组以形状为基础的图片处理操作。在形态学操作中,会对输入图片应用一个结构元素并且生成一张输出图片。
•.最常见的形态学操作有两种:腐蚀和膨胀。它们用途广泛,例如:
•.去除噪声
•.将图片中单独的元素分割开,或者将图片中处于分离状态的元素连接起来。
•.寻找图片中特别亮的区域(intensity bumps)或空洞(holes)
•.我们会使用以下图片作为示例来简要说明一下膨胀和腐蚀操作:
以下是这篇教程对应的源代码。妳可以到 这里 直接下载。
#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;
/** 函数头 */
void Erosion( int, void* );
void Dilation( int, void* );
/** @function main */
int main( int argc, char** argv )
{
/// 载入一张图片
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 );
/// 创建腐蚀参数滑动条
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 );
/// 创建膨胀参数滑动条
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 );
/// 按照默认参数启动操作过程
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 );
}
1. 这其中的大部分东西都是妳已经学过的东西(如果还有不懂的,请重新阅读之前章节里的教程)。让我们来看看这个程序的总体结构:
•.载入一张图片(可以是RGB格式或灰度图格式)
•.创建两个窗口(一个用于输出膨胀结果,一个用于输出腐蚀结果)
•.为每个操作创建2个滑动条:
•.第一个滑动条“Element”,返回的是用于腐蚀操作的erosion_elem或用于膨胀操作的dilation_elem
•.第二个滑动条“Kernel size”,返回的是erosion_size或dilation_size,分别用于对应的腐蚀或膨胀操作。
•.每当我们拖动任意一个滑动条时,就会调用对应的Erosion或Dilation函数,该函数会根据当前的滑动条的值来更新输出图片的内容。
让我们来分析一下这两个函数:
2. 腐蚀:
/** @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函数。从代码中可以看到,它需要3个参数:
•. src: 源图片
•. erosion_dst: 输出的图片
•. element: 这是用来进行腐蚀操作的内核。如果我们不指定它,那么默认值就是一个简单的3x3矩阵。否则的话,我们可以自行指定它的形状。为了做到这一点,我们需要使用 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
然后,我们只需要指定内核的尺寸及锚点。如果没有指定的话,就会假设中心点作为锚点。
•.说完了。现在我们可以对图片进行腐蚀操作了。
注意
另外还有一个参数,可以用来在一次运行过程中进行多次(迭代)腐蚀操作。不过,我们在这个简单的教程中没有使用这个选项。妳可以去看参考文档以了解更多细节。
3. 膨胀:
以下是膨胀部分的代码。可以看到,它与腐蚀的代码完全类似。这里,我们同样可以定义内核形状、锚点以及操作子的尺寸。
/** @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 );
}
未知美人
HxLauncher: Launch Android applications by voice commands