OpenCV_图像膨胀腐蚀与形态学操作及具体应用详解
在本教程中,您将学习如何:
- 应用两个非常常见的形态运算符:腐蚀和膨胀:
-
- cv::erode
- cv::dilate
- 使用OpenCV函数cv :: morphologyEx应用形态转换,如:
- 开运算
- 闭运算
- 形态学梯度
- 顶帽运算
- 黑帽运算
形态作业
- 简而言之:一组基于形状处理图像的操作。形态操作将结构元素应用于输入图像并生成输出图像。
- 最基本的形态作用是:腐蚀和膨胀。它们有广泛的用途,即:
- 消除噪音
- 隔离单个元素并连接图像中的不同元素。
- 查找图像中的强度凸点或孔
1.腐蚀操作(erode)
腐蚀操作可以将图像中的边缘“腐蚀”掉,使其变得更加平滑。它的原理是使用一个称为结构元素(Structuring Element)的小型矩阵,在图像上滑动并检查像素与结构元素的对应位置是否满足某种条件(通常是“与”操作)。如果像素值全部满足条件,则中心像素值保持不变,否则被腐蚀为0。这一过程可以用来消除小型噪声、分离接触对象、以及缩小物体等。
在 OpenCV 中,腐蚀操作的函数是 erode()。下面是它的语法格式和含义:
函数:
erode( src, dst, kernel);
src:表示输入图像,即待腐蚀的图像,应为灰度图像或者单通道二值图像。
dst:表示输出图像
kernel:表示结构元素,这是我们将用来执行操作的内核。如果我们不指定,
默认是一个简单的3x3矩阵。否则,我们可以指定它的形状。为此,我们需要使用
函数cv :: getStructuringElement:
腐蚀操作的基本思想是,对于给定的结构元素,在图像上滑动并检查像素与结构元素的对应位置是否满足某种条件。如果像素值全部满足条件,则中心像素值保持不变,否则被腐蚀为0。
- 这个操作是扩张的姊妹。它计算给定内核区域的局部最小值。
- 当内核在图像上扫描时,我们计算由重叠的最小像素值,并用该最小值替换锚点下的图像像素。BB
- 对于扩张的例子,我们可以将侵蚀算子应用于原始图像(如上所示)。您可以在下面的结果中看到,图像的明亮区域(背景,显然)变得更薄,而黑暗区域(“写作”)变得更大。
以相似的方式,通过对反转的原始图像(具有尺寸的矩形结构元素的两次侵蚀)施加腐蚀操作来产生相应的图像3x3:
左图:原图反转,右图:造成腐蚀
代码如下:
void callback_Demo(int, void* userdata) {
Mat dst;
Mat image = *((Mat*)userdata);
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(
MORPH_RECT,
Size(s, s),
Point(-1, -1));
erode(image, dst, structureElement, Point(-1, -1), 1);
imshow(OUTPUT_WINDOW, dst);
return;
}
2.膨胀操作(dilate)
膨胀操作是图像形态学处理中的一种基本操作,通常用于增加或扩展图像中的白色区域(前景对象)。它的原理是在图像上滑动一个结构元素(通常是一个小的矩形或圆形内核),将内核下方的像素值替换为内核下方区域内的最大像素值。因此,它会使图像中的白色区域变得更大。膨胀操作常用于填充图像中的空洞、连接相邻的对象以及消除图像中的噪声。
在OpenCV中,膨胀操作可以通过dilate()函数实现。该函数需要传入待处理的图像、结构元素(通常是一个矩形或圆形内核)以及迭代次数作为参数。迭代次数表示膨胀操作的次数,通常设置为1即可。
函数:
dilate( src, dst, kernel);
src:表示输入图像,即待膨胀的图像,应为灰度图像或者单通道二值图像。
dst:表示输出图像
kernel:表示结构元素,这是我们将用来执行操作的内核。如果我们不指定,
默认是一个简单的3x3矩阵。否则,我们可以指定它的形状。为此,我们需要使用
函数cv :: getStructuringElement:
- 该操作包括将图像与某些内核(B)进行卷积,其可以具有任何形状或尺寸,通常为正方形或圆形。AB
- 内核具有定义的锚点,通常是内核的中心。B
- 当内核在图像上扫描时,我们计算由B重叠的最大像素值,并用该最大值替换锚点位置中的图像像素。您可以推断,这种最大化的操作会使图像中的亮区“增长”(因此称为扩张)。以上图为例。应用扩张我们可以得到:BB
背景(明亮)扩大了字母的黑色地区。
为了更好地把握想法并避免可能的混乱,在另一个例子中,我们已经将原始图像倒过来,如白色的对象现在是这个字母。我们已经执行了两个具有大小的矩形结构元素的扩张3x3。
左图:原图反转,右图:产生扩张
代码如下:
void callback_Demo(int, void* userdata) {
Mat dst;
Mat image = *((Mat*)userdata);
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
dilate(image,dst,structureElement,Point(-1,-1),1);
imshow(OUTPUT_WINDOW, dst);
return;
}
全部代码如下:
char OUTPUT_WINDOW[] = "output image";
int element_size = 3;
int max_size = 21;
void callback_Demo(int, void* userdata);
void callback_Demo(int, void* userdata) {
Mat dst;
Mat image = *((Mat*)userdata);
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
dilate(image,dst,structureElement,Point(-1,-1),1);
//erode(image, dst, structureElement, Point(-1, -1), 1);
//threshold(image,dst, element_size, max_size, THRESH_OTSU);
imshow(OUTPUT_WINDOW, dst);
return;
}
void QuickDemo::eleven(Mat& image) {
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
namedWindow(OUTPUT_WINDOW, WINDOW_AUTOSIZE);
createTrackbar("element size :", OUTPUT_WINDOW, &element_size, max_size, callback_Demo, &image);
callback_Demo(10, &image);
}
在前面的教程中,我们介绍了两种基本的形态学操作:
- 腐蚀
- 膨胀
基于这两个,我们可以对我们的图像进行更复杂的转换。在这里,我们简要讨论OpenCV提供的5个操作:
3.开运算—先腐蚀后膨胀
开运算是先进行腐蚀操作,再进行膨胀操作。它主要用于去除小的噪点,并保持前景物体的整体形状。
函数:
morphologyEx(mask_image, opening_image, MORPH_OPEN, element);
示例代码:
void QuickDemo::twelve(Mat& image) {
Mat dst;
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
morphologyEx(image, dst, MORPH_OPEN, kernel);
namedWindow("形态学操作", WINDOW_AUTOSIZE);
imshow("形态学操作", dst);
}
开运算效果:对比腐蚀过后的图像,进行稍微膨胀 补充连接细节
4.闭运算—先膨胀后腐蚀
闭运算与开运算相反,先膨胀后腐蚀,它主要用于填补前景物体中的小孔和连接断开的物体。
void QuickDemo::twelve(Mat& image) {
Mat dst;
Mat kernel = getStructuringElement(MORPH_RECT, Size(10, 10), Point(-1, -1));
morphologyEx(image, dst, MORPH_CLOSE, kernel);
namedWindow("形态学操作", WINDOW_AUTOSIZE);
imshow("形态学操作", dst);
}
闭运算效果:对比膨胀后的图像,边缘稍微细了些
5.形态学梯度(膨胀-腐蚀)
形态学梯度运算是用图像的膨胀图像减腐蚀图像的操作,该操作可以获取原始图像中前景图像的边缘。
- 这是图像的扩张和侵蚀的区别。
-
找到对象的轮廓是有用的,如下所示:
代码如下:
void QuickDemo::twelve(Mat& image) {
Mat dst;
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
morphologyEx(image, dst, MORPH_GRADIENT, kernel);
namedWindow("形态学操作", WINDOW_AUTOSIZE);
imshow("形态学操作", dst);
}
6. 顶帽运算(src-开运算)
顶帽运算是用原始图像减去其开运算图像的操作。顶帽运算能够获取图像的噪声信息,或者得到比原始图像的边缘更亮的边缘信息。
代码如下:
void QuickDemo::twelve(Mat& image) {
Mat dst;
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
morphologyEx(image, dst, MORPH_TOPHAT, kernel);
namedWindow("形态学操作", WINDOW_AUTOSIZE);
imshow("形态学操作", dst);
}
7.黑帽运算(闭运算-src)
黑帽运算是用闭运算图像减去原始图像的操作。黑帽运算能够获取图像内部的小孔,或前景色中的小黑点,或者得到比原始图像的边缘更暗的边缘部分。
void QuickDemo::twelve(Mat& image) {
Mat dst;
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
morphologyEx(image, dst, MORPH_BLACKHAT, kernel);
namedWindow("形态学操作", WINDOW_AUTOSIZE);
imshow("形态学操作", dst);
}