OpenCV实战 | 基于形态学运算提取图像中的音符

Posted 行路南

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV实战 | 基于形态学运算提取图像中的音符相关的知识,希望对你有一定的参考价值。

图像形态学运算,顾名思义是应用形态学操作改变图像中物体的形状的过程。其中形态学操作比较基础的是膨胀、腐蚀、开运算和闭运算;形态学操作的对象通常是二值化图像。

本文会先介绍形态学中常见的操作的原理部分,然后介绍在OpenCV中这些操作的函数和参数含义,最后通过一个提取图像中音符的样例来贯穿全部的内容。

1 形态学操作

1.1 腐蚀

腐蚀过程是将一个核与一个图像进行卷积,其中核可以是任何的形状,比如大小为 3 ∗ 3 3 * 3 33的正方形核,也可以是大小为 5 ∗ 1 5 * 1 51的长条形核。核有一个参考点,参考点位于核的正中心。

将核与图像进行卷积,就是从左到右、从上到下滑动窗口运算的过程。在这个过程中,对于腐蚀操作,每次计算核在图像中覆盖的区域的最小值,并将这个最小值赋值给核的参考点指定的像素。

以下图为例,当核的参考点位于原图的第2行第8列时(从0开始),此时整个核的覆盖区域就是以参考点为中心的正方形区域,在这个区域内的最小值为0,那么腐蚀后的图像中第2行第8列的值就是0;当核的参考点位于第4行第4列时,此时整个核的覆盖区域的最小值是255,那么腐蚀后的图像中第4行第4列的值就是255。

图1 腐蚀

可以看到经过腐蚀后的图像,消除了一些斑点噪音,同时确保图中较大的区域仍然存在,最终得到我们想要的区域。

在下文的示例中,我们还会演示一个提取音符的例子,在那个例子中,我们会设计一种核结构,使得图中所有的横线都作为噪音被清除掉,也就达到了提取音符的目的。

1.2 膨胀

膨胀和腐蚀相反,膨胀是将核和一个图像进行卷积,计算的是核区域内像素的最大值。

图2 膨胀

此外,膨胀也可以填补凹洞,如下图所示。

图3 膨胀

在试图找到连通分支时通常使用膨胀操作,因为大多数情况下一个大的区域可能被一些噪音等分割为多个区域,而通过膨胀操作能够使这些多个区域结合在一起。

1.3 开运算

开运算,是先进行腐蚀操作,再进行膨胀操作。开运算的效果是消除了高于临近点的孤立点

图4 开运算的过程

1.4 闭运算

闭运算,是先膨胀后腐蚀。这里我们的输入图像和1.3节的输入图像一样,在下图中我们可以看到先膨胀后腐蚀的效果,即消除了低于临近点的孤立点

图5 闭运算的过程

2 核

在上文中,我们都是使用大小为 3 ∗ 3 3*3 33的核来进行膨胀或者腐蚀的操作。(有些教材中,核也称为结构元素)

在实际使用中,核的选择是非常重要的一个部分,针对不同的情况,我们需要灵活需要不同的核,比如矩形的核、十字交叉的核,菱形的核等等。

同时我们也可以根据自己的需要自定义自己的核。

2.1 核具体是什么

所谓核,就是仅仅由0和1组成的一个矩阵,可以具有任意的形状和大小,通常比我们要处理的图像要小得多。

在核中通过值为1的像素定义了核的邻域,表明了核的形状。核的中心像素,称为核的参考点,或者叫原点,表示正在处理的像素。

2.2 几种常见的核

图6 几种常见的核结构

上图中展示了常用的正方形核、长方形核、菱形核、十字交叉核,此外还有圆盘核、周期核等等。我们在选择核的时候,需要根据在输入图像中要提取的对象的大小和形状,来选择相对应的核结构。例如,我们想提取图像中的线条,那么选择一个线性结构的核比较合适。

3 在OpenCV中形态学运算的函数

3.1 形态学运算

void cv::morphologyEx	(	InputArray 	src,
                            OutputArray 	dst,
                            int 	op,
                            InputArray 	kernel,
                            Point 	anchor = Point(-1,-1),
                            int 	iterations = 1,
                            int 	borderType = BORDER_CONSTANT,
                            const Scalar & 	borderValue = morphologyDefaultBorderValue() 
						)		

执行高级形态转换。功能 cv: : morphologyEx 可以使用腐蚀和膨胀作为基本操作进行高级形态转换。任何操作都可以就地完成。对于多通道图像,每个通道都是独立处理的。

参数说明:

src源图像。通道的数量可以是任意的。深度应该是CV_8U, CV_16U, CV_16S, CV_32F or CV_64F 中的一个
dst与源图像大小和类型相同的目标图像。
op形态学运算的类型; 包括MORPH_ERODE、MORPH_DILATE 、MORPH_OPEN 、MORPH_CLOSE 等
kernel核(结构元素) 可以通过 getStructuringElement.函数来创建,在下文详细说明。
anchor核的参考点位置,默认值是负值,表示位于内核中心。
iterations应用腐蚀和膨胀的次数,默认为1

3.2 核(结构元素)


Mat cv::getStructuringElement	(	int 	shape,
                                    Size 	ksize,
                                    Point 	anchor = Point(-1,-1) 
                                )		

返回用于形态学操作的指定大小和形状的结构元素。

该功能构造和返回的结构元素,可以进一步通过腐蚀,扩张或形态。但是您也可以自己构造一个任意的二进制掩码,并使用它作为结构元素。

参数说明:

shape核的形状,支持三种。分别是MORPH_RECT、MORPH_CROSS、MORPH_ELLIPSE
ksize核的大小
anchor元素内的锚定位置。默认值(−1.−1) 表示锚点位于中心。请注意,只有十字形图元的形状取决于锚定位置。在其他情况下,锚仅仅调节形态学操作的结果被移动的程度。

4 C++样例

	
#include <opencv2/opencv.hpp>


int main(int argc, char** argv)

    // 第一步,读取原始图像
    cv::Mat img = cv::imread("/home/lxn/图片/src.png");
    cv::imshow("ori img", img);
    cv::waitKey(0);

    // 第二步,转灰度图
    cv::Mat gray;
    cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
    cv::imshow("gray", img);
    cv::waitKey(0);

    // 第三步,取反
    // 需特别注意的是,原始图像中物体是黑色,背景是白色;
    // 在膨胀或者腐蚀操作,我们针对的都是高亮的物体,所以为了便于理解,我们对物体的像素值做一个取反操作(value = 255 - value)
    cv::Mat bw_gray;
    cv::bitwise_not(gray, bw_gray);
    cv::imshow("bw_gray", bw_gray);
    cv::waitKey(0);

    // 第四步,二值化
    cv::Mat threshold_gray;
    cv::threshold(bw_gray, threshold_gray, 100, 255, cv::THRESH_BINARY);
    cv::imshow("threshold_gray", threshold_gray);
    cv::waitKey(0);

    // 第五步,提取垂直线(过滤掉水平的横线,得到音符).这里的核要既保证清除掉横线,同时小的音符又能够保留。所以核的高度选择大于横线像素高度的最小值
    cv::Mat vertical;
    cv::Mat vertical_kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1, 4));
    cv::morphologyEx(threshold_gray, vertical, cv::MORPH_OPEN, vertical_kernel);
    cv::imshow("vertical", vertical);
    cv::waitKey(0);

    // 第六步, 取反,得到前景为黑,背景为白的图像
    cv::bitwise_not(vertical, vertical);
    cv::imshow("bw_vertical", vertical);
    cv::waitKey(0);
    
    return 0;

图7 原图

图8 灰度图

图9 取反的灰度图

图10 二值化图

图11 横线过滤图

图12 再次取反的最终结果

以上是关于OpenCV实战 | 基于形态学运算提取图像中的音符的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV实战 | 基于形态学运算提取图像中的音符

youcans 的 OpenCV 例程200篇116. 形态学操作之闭运算

youcans 的 OpenCV 例程200篇117. 形态学操作之顶帽运算

youcans 的 OpenCV 例程 200 篇118. 形态学操作之底帽运算

youcans 的 OpenCV 例程 200 篇118. 形态学操作之底帽运算

OpenCV实战(11)——形态学变换详解