Opencv图像处理---膨胀与腐蚀

理论

  •  形态学操作将结构元素应用于输入图像并生成输出图像。
  • 最基本的形态学操作是两个:侵蚀和膨胀。他们具有广泛的用途:
  1. 消除噪音
  2. 隔离单个元素并连接图像中的不同元素。
  3. 查找图像中的强度凸起或孔

膨胀

  • 该操作包括将图像A与一些内核(B)卷积,其可以具有任何形状或大小,通常是正方形或圆形。
  • 内核B有一个定义的锚点,通常是内核的中心。
  • 当在图像上扫描内核B时,我们计算由B重叠的最大像素值,并用该最大值替换锚点位置中的图像像素。 正如您可以推断的那样,这种最大化操作会导致图像中的明亮区域“增长”(因此称为扩张)。即背景(明亮)在字母的黑色区域周围扩张。

                                                                           

腐蚀

  •  这样做是为了计算内核区域的局部最小值。
  • 当在图像上扫描内核B时,我们计算由B重叠的最小像素值,并用该最小值替换锚点下的图像像素。
  • 我们可以将侵蚀算子应用于原始图像(如上所示)。 您可以在下面的结果中看到图像的明亮区域(显然是背景)变得更薄,而暗区域(“书写”)变得更大。

                                                                             

代码

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#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* );
int main( int, char** argv )
{
  src = imread( argv[1] );
  if( src.empty() )
    { return -1; }
  namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );
  namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );
  moveWindow( "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;
}
void Erosion( int, void* )
{
  int erosion_type = 0;
  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 );
}
void Dilation( int, void* )
{
  int dilation_type = 0;
  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 );
}

解释

让我们查看一下程序的一般结构:

  • 加载图像(可以是BGR或灰度)
  • 创建两个窗口(一个用于膨胀,另一个用于侵蚀)
  • 为每个操作创建一组02轨道栏:
  1. 第一个轨道栏“Element”返回erosion_elem或dilation_elem
  2. 第二个轨道栏“内核大小”返回相应操作的erosion_size或dilation_size。
  • 每次移动任何滑块时,都会调用用户的Erosion或Dilation函数,它将根据当前的trackbar值更新输出图像。

腐蚀

执行侵蚀操作的函数是cv :: erode。 我们可以看到,它收到三个参数:

  • src:源图像
  • erosion_dst:输出图像
  • element:这是我们将用于执行操作的内核。 如果我们不指定,则默认为简单的3x3矩阵。 否则,我们可以指定其形状。 为此,我们需要使用函数cv :: getStructuringElement:
  • 我们可以为内核选择三种形状中的任何一种:
  1. 矩形内核:MORPH_RECT
  2. 十字架内核:MORPH_CROSS
  3. 椭圆内核:MORPH_ELLIPSE

膨胀

代码如下。 正如您所看到的,它与侵蚀代码片段完全相似。 在这里,我们还可以选择定义我们的内核,它的锚点以及要使用的运算符的大小。

效果

猜你喜欢

转载自blog.csdn.net/LYKymy/article/details/83153122