StupidBeauty
Read times:851Posted at:Sun Dec 22 05:42:21 2013
- no title specified

OpenCV2.4.7.0文档翻译:腐蚀与膨胀,Eroding and Dilating

目标

在这篇教程中,妳将学到:

  • •.如何应用两种常见的形态学操作:膨胀和腐蚀。对于这个目标,妳将使用以下的OpenCV函数:

华丽的理论

注意

以下的理论说明内容,来自于Bradski 和Kaehler 撰写的Learning OpenCV 一书。

形态学操作

  • •.简单来说:一组以形状为基础的图片处理操作。在形态学操作中,会对输入图片应用一个结构元素并且生成一张输出图片。

  • •.最常见的形态学操作有两种:腐蚀和膨胀。它们用途广泛,例如:

    • •.去除噪声

    • •.将图片中单独的元素分割开,或者将图片中处于分离状态的元素连接起来。

    • •.寻找图片中特别亮的区域(intensity bumps)或空洞(holes)

  • •.我们会使用以下图片作为示例来简要说明一下膨胀和腐蚀操作:

腐蚀

  • •.这个操作与膨胀类似。不过它所做的是计算出内核所覆盖的区域中的最小值。

  • •.在将内核B放在图片上扫描的过程中,我们会计算出被B覆盖的那些像素点的最小值,并且使用该最小值来替换图片中对应于锚点处的像素的值。

  • •.同样地,我们可以对上面的示例图片做腐蚀操作。从下面的结果中可以看出,图片中的明亮区域(显然就是背景了),变小了,而黑暗区域(“手写”的部分)变大了。

代码

以下是这篇教程对应的源代码。妳可以到 这里 直接下载。

#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. 1. 这其中的大部分东西都是妳已经学过的东西(如果还有不懂的,请重新阅读之前章节里的教程)。让我们来看看这个程序的总体结构:

    • •.载入一张图片(可以是RGB格式或灰度图格式)

    • •.创建两个窗口(一个用于输出膨胀结果,一个用于输出腐蚀结果)

    • •.为每个操作创建2个滑动条:

      • •.第一个滑动条“Element”,返回的是用于腐蚀操作的erosion_elem或用于膨胀操作的dilation_elem

      • •.第二个滑动条“Kernel size”,返回的是erosion_sizedilation_size,分别用于对应的腐蚀或膨胀操作。

    • •.每当我们拖动任意一个滑动条时,就会调用对应的ErosionDilation函数,该函数会根据当前的滑动条的值来更新输出图片的内容。

    让我们来分析一下这两个函数:

  1. 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

        然后,我们只需要指定内核的尺寸及锚点。如果没有指定的话,就会假设中心点作为锚点。

    • •.说完了。现在我们可以对图片进行腐蚀操作了。

    注意

    另外还有一个参数,可以用来在一次运行过程中进行多次(迭代)腐蚀操作。不过,我们在这个简单的教程中没有使用这个选项。妳可以去看参考文档以了解更多细节。

  1. 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 );

}

结果

  • •.编译以上代码,然后以一张图片作为参数来执行它。例如,使用以下图片:

    以下是处理结果。自然地,改变滑动条的值会产生不一样的输出结果。亲自尝试一下吧!妳还可以加入第三个滑动条,以控制迭代次数。

未知美人

Your opinions
Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands