OpenCV进阶---形态学处理

1. 学习目标:

目标 OpenCV函数
腐蚀 erode
膨胀 dilate
2. OpenCV理论 简而言之:一组基于形状处理图像的操作。 形态学操作将结构元素应用于输入图像并生成输出图像。
最基本的形态学操作是:侵蚀和膨胀。 它们有广泛的用途,即:
1.消除噪音
2.隔离单个元素并连接图像中的不同元素。
3.查找图像中的强度凸起或孔
我们将使用以下图像作为示例,简要解释膨胀和侵蚀:
OpenCV进阶---形态学处理
文章图片

dilate(膨胀)
  • 该操作包括将图像A与一些内核(B)卷积,该卷积可以具有任何形状或大小,通常是正方形或圆形。
  • 内核B有一个定义的锚点,通常是内核的中心。
  • 当在图像上扫描内核B时,我们计算由B重叠的最大像素值,并用该最大值替换锚点位置中的图像像素。 这种最大化操作会导致图像中的明亮区域“增长”(因此称为扩张)。
  • 扩张操作是:dst(x,y)= max(x',y'):element(x',y')≠0 src(x + x',y + y')
    膨胀处理:
  • OpenCV进阶---形态学处理
    文章图片

Erosion
同理,用邻域中的最小值代替
OpenCV进阶---形态学处理
文章图片


3. Code
#include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" #include using namespace cv; using namespace std; 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 argc, char** argv ) { CommandLineParser parser( argc, argv, "{@input | ../data/LinuxLogo.jpg | input image}" ); src = https://www.it610.com/article/imread( parser.get("@input" ), IMREAD_COLOR ); if( src.empty() ) { cout << "Could not open or find the image!\n" << endl; cout << "Usage: " << argv[0] << " " << endl; 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 ); }

4. 代码详解 erosion
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 ); }

执行侵蚀操作的函数是cv :: erode。 我们可以看到,它有三个参数:
  • src:源图像
  • erosion_dst:输出图像
  • element:这是我们将用于执行操作的内核。 如果我们不指定,则默认为简单的3x3矩阵。 否则,我们可以指定其形状。 为此,我们需要使用函数cv :: getStructuringElement:
  • OpenCV进阶---形态学处理
    文章图片

  • 我们可以为内核选择三种形状中的任何一种:
    【OpenCV进阶---形态学处理】矩形框:MORPH_RECT
    十字:MORPH_CROSS
    椭圆:MORPH_ELLIPSE
    然后,我们只需要指定内核的大小和锚点。 如果未指定,则假定它位于中心。
Result OpenCV进阶---形态学处理
文章图片

原图
OpenCV进阶---形态学处理
文章图片


    推荐阅读