OpenCV的侵蚀和扩张

目标

在本教程中,您将学习如何:

注意

下面的解释属于 Bradski 和 Kaehler 合著的《学习 OpenCV》一书。

形态学操作

  • 简而言之:一组基于形状处理图像的操作。形态学操作将结构化元素应用于输入图像并生成输出图像。
  • 最基本的形态操作是:侵蚀和扩张。它们具有广泛的用途,即:
    • 消除噪音
    • 隔离单个元素并连接图像中的不同元素。
    • 在图像中发现强度凸起或孔洞
  • 我们将以下图为例,简要解释扩张和侵蚀:

    Morphology_1_Tutorial_Theory_Original_Image.png

扩张

  • 此操作包括将图像 与一些内核 (B) 卷积,该内核可以具有任何形状或大小,通常是正方形或圆形。一个B
  • 内核 B 有一个定义的锚点,通常是内核的中心。B
  • 当内核 B 在图像上扫描时,我们计算与 B 重叠的最大像素值,并将锚点位置的图像像素替换为该最大值。可以推断,这种最大化操作会导致图像中的明亮区域“增长”(因此称为扩张)。BB
  • 膨胀操作为: \texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')dst(x,y)=麦克斯(x′,y′):元素(x′,y′)≠0src(x+x′,y+y′)
  • 以上图为例。应用扩张,我们可以得到:

    Morphology_1_Tutorial_Theory_Dilation.png

  • 字母的明亮区域在背景的黑色区域周围扩张。

侵蚀

  • 这种手术是扩张的姊妹。它计算给定内核面积的局部最小值。
  • 当内核 B 在图像上扫描时,我们计算与 B 重叠的最小像素值,并将锚点下的图像像素替换为该最小值。BB
  • 侵蚀操作为: \texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')dst(x,y)=分钟(x′,y′):元素(x′,y′)≠0src(x+x′,y+y′)
  • 与膨胀示例类似,我们可以将侵蚀算子应用于原始图像(如上所示)。您可以在下面的结果中看到,图像的明亮区域变薄,而暗区变大。

    Morphology_1_Tutorial_Theory_Erosion.png

法典

C++爪哇岛蟒

本教程的代码如下所示。您也可以在此处下载

#include“opencv2/imgproc.hpp
#include“opencv2/highgui.hpp
#include < iostream>
使用命名空间 CV;
使用命名空间 std;
垫子 src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int 常量 max_elem = 2;
int 常量 max_kernel_size = 21;
无效侵蚀( intvoid* );
无效扩张( intvoid* );
int main( int argc, char** argv )
{
CommandLineParser 解析器( argc, argv, “{@input |Linux徽标.jpg |输入图像}” );
src = imreadsamples::findFile( parser.get<String>( “@input” ) ), IMREAD_COLOR );
if( src.() )
{
cout << “无法打开或找到图像!\n” << endl;
cout << “用法:” << argv[0] << “ <输入图像>” << endl;
返回 -1;
}
namedWindow“侵蚀演示”WINDOW_AUTOSIZE );
namedWindow“膨胀演示”WINDOW_AUTOSIZE );
moveWindow“膨胀演示”, src.cols, 0 );
createTrackbar( “元素:\n 0: 矩形 \n 1: 十字 \n 2: 椭圆”, “侵蚀演示”
&erosion_elem、max_elem、
侵蚀 );
createTrackbar( “内核大小:\n 2n +1”, “侵蚀演示”
&erosion_size、max_kernel_size、
侵蚀 );
createTrackbar( “元素:\n 0: 矩形 \n 1: 十字 \n 2: 椭圆”, “膨胀演示”
&dilation_elem、max_elem、
扩张 );
createTrackbar( “内核大小:\n 2n +1”, “膨胀演示”
&dilation_size、max_kernel_size、
扩张 );
侵蚀( 0, 0 );
扩张( 0, 0 );
waitKey(0);
返回 0;
}
无效侵蚀( intvoid* )
{
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 元素 = getStructuringElement( erosion_type,
尺寸( 2*erosion_size + 1, 2*erosion_size+1 ),
点( erosion_size, erosion_size ) );
erode( src, erosion_dst, element );
imshow“侵蚀演示”, erosion_dst );
}
无效扩张( intvoid* )
{
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 元素 = getStructuringElement( dilation_type,
尺寸( 2*dilation_size + 1, 2*dilation_size+1 ),
( dilation_size, dilation_size ) );
dilate( src, dilation_dst, element );
imshow“扩张演示”, dilation_dst );
}

解释

C++爪哇岛蟒

这里展示的大部分材料都是微不足道的(如果您有任何疑问,请参阅前面部分的教程)。让我们检查一下 C++ 程序的一般结构:

int main( int argc, char** argv )
{
CommandLineParser parser( argc, argv, “{@input |Linux徽标.jpg |输入图像}” );
src = imreadsamples::findFile( parser.get<String>( “@input” ) ), IMREAD_COLOR );
if( src.() )
{
cout << “无法打开或找到图像!\n” << endl;
cout << “用法:” << argv[0] << “ <输入图像>” << endl;
返回 -1;
}
namedWindow“侵蚀演示”WINDOW_AUTOSIZE );
namedWindow“膨胀演示”WINDOW_AUTOSIZE );
moveWindow“膨胀演示”, src.cols, 0 );
createTrackbar( “元素:\n 0: 矩形 \n 1: 十字 \n 2: 椭圆”, “侵蚀演示”
&erosion_elem、max_elem、
侵蚀 );
createTrackbar( “内核大小:\n 2n +1”, “侵蚀演示”
&erosion_size、max_kernel_size、
侵蚀 );
createTrackbar( “元素:\n 0: 矩形 \n 1: 十字 \n 2: 椭圆”, “膨胀演示”
&dilation_elem、max_elem、
扩张 );
createTrackbar( “内核大小:\n 2n +1”, “膨胀演示”
&dilation_size、max_kernel_size、
扩张 );
侵蚀( 0, 0 );
扩张( 0, 0 );
waitKey(0);
返回 0;
}
  1. 加载图像(可以是 BGR 或灰度)
  2. 创建两个窗口(一个用于膨胀输出,另一个用于侵蚀)
  3. 为每个操作创建一组两个跟踪栏:
    • 第一个跟踪栏“Element”返回 erosion_elem 或 dilation_elem
    • 第二个跟踪栏“内核大小”返回相应操作的erosion_sizedilation_size
  4. 调用一次侵蚀和扩张以显示初始图像。

每次我们移动任何滑块时,都会调用用户的函数 Erosion 或 Dilation,它将根据当前的轨迹栏值更新输出图像。

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

侵蚀函数
无效侵蚀( intvoid* )
{
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 元素 = getStructuringElement( erosion_type,
尺寸( 2*erosion_size + 1, 2*erosion_size+1 ),
点( erosion_size, erosion_size ) );
erode( src, erosion_dst, element );
imshow“侵蚀演示”, erosion_dst );
}

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

  • src:源图片
  • erosion_dst:输出图像
  • element:这是我们将用来执行操作的内核。如果我们不指定,则默认值为简单矩阵。否则,我们可以指定它的形状。为此,我们需要使用函数 cv::getStructuringElement :3x3

    Mat 元素 = getStructuringElement( erosion_type,
    尺寸( 2*erosion_size + 1, 2*erosion_size+1 ),
    点( erosion_size, erosion_size ) );

    我们可以为内核选择三种形状中的任何一种:

    • 长方形盒子:MORPH_RECT
    • 十字架:MORPH_CROSS
    • 椭圆:MORPH_ELLIPSE

    然后,我们只需要指定内核的大小和锚点。如果未指定,则假定它位于中心。

仅此而已。我们已准备好对我们的形象进行侵蚀。

扩张功能

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

无效扩张( intvoid* )
{
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 元素 = getStructuringElement( dilation_type,
尺寸( 2*dilation_size + 1, 2*dilation_size+1 ),
( dilation_size, dilation_size ) );
dilate( src, dilation_dst, element );
imshow“扩张演示”, dilation_dst );
}

注意

此外,还有其他参数允许您一次执行多个侵蚀/扩张(迭代),还可以设置边界类型和值。但是,我们在这个简单的教程中没有使用它们。您可以查看参考资料了解更多详情。

结果

编译上面的代码并使用图像作为参数执行它(如果使用 python,则运行脚本)。如果不提供图像作为参数,则将使用默认示例图像 (LinuxLogo.jpg)。

例如,使用此图像:

Morphology_1_Tutorial_Original_Image.jpg

我们得到下面的结果。自然,改变轨迹栏中的索引会给出不同的输出图像。试试看吧!您甚至可以尝试添加第三个跟踪栏来控制迭代次数。

Morphology_1_Result.jpg

(根据编程语言的不同,输出可能会略有不同或只有 1 个窗口)

   在线教程

有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

请添加图片描述

人工智能书籍

第一阶段:零基础入门(3-6个月)

新手应首先通过少而精的学习,看到全景图,建立大局观。 通过完成小实验,建立信心,才能避免“从入门到放弃”的尴尬。因此,第一阶段只推荐4本最必要的书(而且这些书到了第二、三阶段也能继续用),入门以后,在后续学习中再“哪里不会补哪里”即可。

第二阶段:基础进阶(3-6个月)

熟读《机器学习算法的数学解析与Python实现》并动手实践后,你已经对机器学习有了基本的了解,不再是小白了。这时可以开始触类旁通,学习热门技术,加强实践水平。在深入学习的同时,也可以探索自己感兴趣的方向,为求职面试打好基础。

第三阶段:工作应用

这一阶段你已经不再需要引导,只需要一些推荐书目。如果你从入门时就确认了未来的工作方向,可以在第二阶段就提前阅读相关入门书籍(对应“商业落地五大方向”中的前两本),然后再“哪里不会补哪里”。

 有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在这里插入图片描述

  • 56
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值