【 imgproc 模块. 图像处理】腐蚀与膨胀(Eroding and Dilating)
一、形态学操作
-
简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将结构元素 作用于输入图像来产生输出图像。
-
最基本的形态学操作有两种:腐蚀与膨胀(Erosion 与 Dilation)。 主要应用有:
- 消除噪声
- 分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
- 寻找图像中的明显的极大值区域或极小值区域。
-
教程中主要通过以下图像讨论膨胀与腐蚀操作(注:图像中的字母为黑色,背景为白色,而不是一般意义的背景为黑色,前景为白色):
二、膨胀
-
此操作将图像 与任意形状的内核 (),通常为正方形或圆形,进行卷积。
-
内核 有一个可定义的 锚点, 通常定义为内核中心点。
-
进行膨胀操作时,将内核 划过图像,将内核 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:
背景(白色)膨胀,而黑色字母缩小了。如果对图像取反,再膨胀,字母就会变大(膨胀)。
API:
@param src input image; the number of channels can be arbitrary, but the depth should be one of CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. @param dst output image of the same size and type as src. @param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular structuring element is used. Kernel can be created using #getStructuringElement @param anchor position of the anchor within the element; default value (-1, -1) means that the anchor is at the element center. @param iterations number of times dilation is applied. @param borderType pixel extrapolation method, see #BorderTypes @param borderValue border value in case of a constant border @sa erode, morphologyEx, getStructuringElement */ CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
三、腐蚀
-
腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。
-
进行腐蚀操作时,将内核 划过图像,将内核 覆盖区域的最小相素值提取,并代替锚点位置的相素。
-
以与膨胀相同的图像作为样本,我们使用腐蚀操作。从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。
API:
@param src input image; the number of channels can be arbitrary, but the depth should be one of CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. @param dst output image of the same size and type as src. @param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular structuring element is used. Kernel can be created using #getStructuringElement. @param anchor position of the anchor within the element; default value (-1, -1) means that the anchor is at the element center. @param iterations number of times erosion is applied. @param borderType pixel extrapolation method, see #BorderTypes @param borderValue border value in case of a constant border @sa dilate, morphologyEx, getStructuringElement */ CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
四、opencv例程
#include"stdafx.h" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include "highgui.h" #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; /** Function Headers */ void Erosion(int, void*); void Dilation(int, void*); /** @function main */ int main(int argc, char** argv) { /// Load 图像 src = imread("膨胀腐蚀例图.png"); //载入图片 if (!src.data) //判断图像数据是否存在 { return -1; } /// 创建显示窗口 namedWindow("Erosion Demo", CV_WINDOW_NORMAL); namedWindow("Dilation Demo", CV_WINDOW_NORMAL); cvMoveWindow("Dilation Demo", src.cols, 0);//将显示窗口左上角移动到显示屏上指定的位置 /// 创建腐蚀 Trackbar /*int createTrackbar(const String& trackbarname, const String& winname, int* value, int count, TrackbarCallback onChange = 0, void* userdata = 0); 参数1:滑动条的名称。 参数2:窗口的名称,就是说这个创建的滑动条所要依附到哪个窗口上。 参数3:表示滑块的位置。在创建时,滑块的初始位置的值就是该指针所指向地址(理解为一个变量)当前的值。 参数4:表示滑块可以滑到的最大值位置。滑块的最小值始终为0。 参数5:TrackbarCallback类型的onChange,它有默认值为0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为 void XXXXX(int, void*); 参数6:void*类型的userdata,它也有默认值为0。这个参数是用户传给回调函数的数据,用来处理滑动条的调用。如果使用的第3个参数value实参是全局变量的话,完全可以不用去管这个userdata参数。 */ 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); /// 创建膨胀 Trackbar 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); /// Default start Erosion(0, 0); Dilation(0, 0); waitKey(0); return 0; } /** @function Erosion */ void Erosion(int, void*) { int erosion_type; 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); } /** @function Dilation */ void Dilation(int, void*) { int dilation_type; 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)); /*这个函数的第一个参数表示内核的形状,有三种形状可以选择。 矩形:MORPH_RECT; 交叉形:MORPH_CORSS; 椭圆形:MORPH_ELLIPSE; 第二和第三个参数分别是内核的尺寸以及锚点的位置。一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。element形状唯一依赖锚点位置,其他情况下,锚点只是影响了形态学运算结果的偏移。 */ ///膨胀操作 dilate(src, dilation_dst, element); imshow("Dilation Demo", dilation_dst); }
One day,I will say
"I did it"