29.提取水平和垂直的线条

本文作者:小嗷

微信公众号:aoxiaoji

简书链接:https://www.jianshu.com/u/45da1fbce7d0

在本篇中,您将学习:

用两个非常常见的形态学算子(即扩张和侵蚀),创建自定义内核,以便在水平和垂直轴上提取直线。为此,您将使用以下OpenCV函数:

erode()

dilate()

getStructuringElement()

在一个例子中,你的目标是从乐谱中提取音乐音符。

(在

第25篇

写道)

本文你会找到以下问题的答案:

用形态学方法提取水平和垂直的线条

CommandLineParser()

adaptiveThreshold()

DestroyWindow()

2.1 理论

形态学操作

形态学是一组图像处理操作,它们基于预定义的结构元素(也称为内核)来处理图像。输出图像中每个像素的值都是基于与相邻的输入图像中对应像素的比较。通过选择内核的大小和形状,您可以构造一个对输入映像的特定形状敏感的形态学操作。

两种最基本的形态学操作是扩张和侵蚀。扩张将像素添加到图像中对象的边界,而侵蚀则恰恰相反。添加或删除像素的数量分别取决于用于处理图像的结构元素的大小和形状。一般来说,这两项行动所遵循的规则如下:

膨胀:输出像素的值是在结构元素的大小和形状范围内的所有像素的最大值。例如,在二进制图像中,如果将内核范围内的输入图像的任何像素设置为1,那么输出图像的相应像素也将设置为1。后者适用于任何类型的图像(例如灰度、bgr等)。

二值图像的膨胀(看不懂就查看第25篇)

灰度图像的膨胀

(其实,就是核心点取3个数中的最大值。看不懂就证明你没好好学)

侵蚀:反之亦然适用于侵蚀操作。输出像素的值是位于结构元素的大小和形状中的所有像素的最小值。请看下图:

二值图像的腐蚀(看不懂就查看第25篇)

灰度图像的侵蚀

结构化元素

如上所述,在任何形态学操作中,用于探测输入图像的结构元素都是最重要的部分。

结构元素是一个只有0和1的矩阵,可以有任意的形状和大小。通常比被处理的图像小得多,而值为1的像素定义邻域。结构元素的中心像素,称为原点,标识感兴趣的像素——被处理的像素。

例如,下面演示了一个7x7大小的菱形结构元素。

菱形结构元素

结构元素可以有许多常见的形状,如线、钻石、磁盘、周期线、圆和大小。通常,您选择的结构元素的大小和形状与您希望在输入映像中处理/提取的对象相同。例如,要在图像中找到线条,请创建一个线性结构元素,稍后您将看到。

3.1 CommandLineParser()

初始化命令行解析器对象

参数解析:

argc :命令行参数的数量(来自main()))

argv[]:命令行参数的数组(来自main()))

keys :描述可接受的命令行参数的字符串(语法参见类描述)

详细说明:

用于命令行解析。 下面的示例演示如何使用CommandLineParser:

上面代码Keys的语法

keys参数是一个包含多个块的字符串,每个块都包含在花括号中,并描述一个参数。每个参数包含由|符号分隔的三个部分:

参数名称是一个空格分隔的选项同义词列表(将参数标记为位置,在其前面加上@符号)

如果没有提供参数,将使用默认值(可以为空)

帮助消息(可以为空)

例如:

注意:没有帮助和时间戳的默认值,因此我们可以使用has()方法检查它们的存在。带默认值的参数被认为总是存在的。在这些情况下使用get()方法来检查它们的实际值。

字符串键如get("@image1")默认返回空字符串,即使默认值为空。使用特殊的默认值强制返回的字符串不能为空。(就像在(“@image2”))

用法

keys的描述

好像在opencv的c版本中,应该是opencv1.0以前,还没有出现CommandLineParser这个类,最近看到opencv2.3后面的版本里自带的samples,很多都用到了CommandLineParser这个类,那么这个类到底有什么作用呢,从命名大概可以猜出这是个命令行解析类。因为我们知道opencv是一个开源库,所以其很少有图形操作方面的api,基本上还是基于命令行执行的。那么这个类的出现主要是方便用户在命令行使用过程中减少工作量,可以在程序文件中直接指定命令行中的参数指令,方便了调试。

我简单写了下面这个例子:

运行结果:

第一行就是这个类的构造函数,前2个参数是命令行传过来的,第3个就是刚刚定义的keys了,keys的结构有一定规律,比如说"{ c | camera | 0 | use camera or not}"都是用大括号和双引号引起来,然后中间的内容分成4断,用”|”分隔开,分别表示简称,文件来源,文件值和帮助语句。第二行和第三行表示打开摄像头和打开文件,文件的文件名等都在keys指针中了。

大概可以看出来用这个类的好处就是很方便,因为以前版本没这个类时,如果要运行带参数的.exe,必须在命令行中输入文件路径以及各种参数,并且输入的参数格式要与代码中的if语句判断内容格式一样,一不小心就输错了,很不方便。另外如果想要更改输入格式的话在主函数文件中要相应更改很多地方。现在有了这个类,只需要改keys里面的内容就可以了,并且可以直接运行,不需要cmd命令行带参运行。最后这个类封装了很多函数,可以直接用,只不过这个本来就是类结构的优点。

3.2 adaptiveThreshold()

对一个数组应用一个自适应阈值。

该函数根据公式将灰度图像转换为二进制图像:

T(x,y)是为每个像素单独计算的阈值(参见adaptiveMethod参数)。 这个函数可以在适当的位置处理图像。

这个函数可以在适当的位置处理图像。

参数解析:

src :8位单通道图像来源。(输入图像)

dst:与src相同大小的目标图像。(输出图像)

maxValue :描述可接受的命令行参数的字符串(语法参见类描述)【向上最大值】

adaptiveMethod:使用自适应阈值算法,请参阅适应性阈值类型。边界复制的边界被用来处理边界。(自适应方法,平均或高斯)

thresholdType:阈值类型必须是THRESHBINARY或THRESHBINARY_INV,请参阅阈值类型。(参考第5篇阈值)

blockSize:用于计算阈值大小的一个像素的邻域尺寸,取值为3、5、7等等(块大小)

C:常量减去平均值或加权平均值(参见下面的详细信息)。通常情况下,它是正的,但也可能是零或负的。

cv::adaptiveThreshold()支持两种自适应方法,即cv::ADAPTIVETHRESHMEANC(平均)和cv::ADAPTIVETHRESHGAUSSIANC(高斯)。在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围bxb大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。(平均和高斯参考第14篇)

测试代码如下:

我们分别使用了平均和高斯两种自适应方法,结果如下:

3.3 DestroyWindow

函数功能:销毁指定的窗口。这个函数通过发送WMDESTROY 消息和 WMNCDESTROY 消息使窗口无效并移除其键盘焦点。这个函数还销毁窗口的菜单,清空线程的消息队列,销毁与窗口过程相关的定时器,解除窗口对剪贴板的拥有权,打断剪贴板器的查看链。

归纳起来,主要有三层意思:

1、该函数销毁一个指定的窗口。

2、如果指定的窗口是一个父窗口,则该函数自动销毁与之管理的子窗口。

3、该函数也用于销毁用CreateDialog 函数创建的非模式对话框。

相关网址:

https://blog.csdn.net/liuy_yy/article/details/7095286

任务:

用形态学方法提取水平和垂直的线条

代码如下:

原图:

下载图片代码:

下载图片:

灰度图代码:

灰度图:

二值图代码:

二值图:

输出图像

现在我们已经准备好应用形态学运算来提取水平和垂直的线条,结果是把乐谱从乐谱中分离出来,但是首先让我们初始化我们将要使用的输出图像:

结构元素

正如我们在理论中所指出的,为了提取我们想要的对象,我们需要创建相应的结构元素。由于我们想要提取水平线,因此对应的结构元素将具有以下形状:

在源代码中,这是由以下代码片段表示的:

同样的道理也适用于垂直的线,有相应的结构元素:

这又一次表示如下:

效果图:

细化边缘/结果 正如你所看到的,我们快到了。然而,在这一点上,你会注意到音符的边缘有点粗糙。出于这个原因,我们需要对边缘进行优化,以获得更平滑的结果:

这个是小实战处理图像(提取直线。当然,具体项目具体看。下期见,感觉好的小伙伴,可以推荐给身边的小伙伴添加公众号,谢谢大家支持。)

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180625G084KE00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券