花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)

除了膨胀和腐蚀,还有更多形态学操作:开操作- open、闭操作- close、形态学梯度- Morphological Gradient、顶帽 – top hat

黑帽 – black hat。

它们都基于morphologyEx()API,通过op的设置选择相应的操作。

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第1张图片

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第2张图片

相关操作

开操作和闭操作都是基于膨胀和腐蚀操作组合形成的。

开操作: 先腐蚀,后膨胀。

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第3张图片

闭操作:先膨胀,后腐蚀

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第4张图片

为了验证开、关操作的作用,首先生成一副类似上图的图像。 

 

#include "pch.h"
#include 
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	Mat src(Size(600, 400), CV_8UC3, Scalar(0, 0, 0));
	//填充白色多边形
	Point pts[1][5] = { Point(50,50),Point(200,50),Point(250,200),Point(50,200),Point(50,50) };
	const Point* ppts[] = { pts[0] };
	const int npts[] = { 5 };
	fillPoly(src, ppts, npts,1, Scalar(255, 255, 255), LINE_AA);
	//在白色多边形上生成小黑洞,利用闭操作,先膨胀-后腐蚀,可以消除这些黑洞
	circle(src, Point(120, 120), 15, Scalar(0, 0, 0), FILLED, LINE_AA);
	//在其他黑色区域生成几个白点,利用开操作,先腐蚀-后膨胀,可以消除这些白点
	RNG rng(getTickCount());
	for (int i = 0; i < 10; i++)
	{
		Point p(rng.uniform(300, 580), rng.uniform(0, 380));
		int r = rng.uniform(3, 15);
		circle(src, p, r, Scalar(255, 255, 255), FILLED, LINE_AA);
	}
	imshow("src", src);
	imwrite("F:\\visual studio\\Image\\src.jpg",src);
	waitKey(0);

}

效果如图:

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第5张图片

接下来对这幅图像进行开、关操作,并观察处理的过程:

#include "pch.h"
#include 
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

void CallBack_Size(int pos, void* userdata);

int main()
{
	Mat src = imread("F:\\visual studio\\Image\\src.jpg");
	if (src.empty())
	{
		cout << "Can't load the image" << endl;
		return -1;
	}
	imshow("src", src);
	int elementSize = 0;
	int maxSize = 21;
	createTrackbar("Size", "src", &elementSize, maxSize, CallBack_Size, (void*)&src);
	waitKey(0);
}

void CallBack_Size(int pos,void* userdata)
{
	Mat src = *((Mat*)userdata);
	int size = 2 * pos + 1;
	Mat dst;
	Mat structureElement = getStructuringElement(MORPH_RECT, Size(size, size), Point(-1, -1));
	morphologyEx(src, dst, MORPH_OPEN, structureElement, Point(-1, -1));
	//morphologyEx(src, dst, MORPH_CLOSE, structureElement, Point(-1, -1));
	imshow("src", dst);

}

 开操作效果如下:先腐蚀后膨胀

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第6张图片

闭操作效果如下:先膨胀后腐蚀

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第7张图片

 

形态学梯度(Morphological Gradient)是膨胀图像与腐蚀图像的之差得到的图像,也是基本梯度。数学表达式如下:

梯度用于刻画目标边界或边缘位于图像灰度级剧烈变化的区域,形态学梯度根据膨胀或者腐蚀与原图作差组合来实现增强结构元素领域中像素的强度,突出高亮区域的外围。计算图像的形态学梯度是形态学重要操作,常常将膨胀和腐蚀基础操作组合起来一起使用实现一些复杂的图像形态学梯度。可以计算的梯度常见如下四种:

基本梯度
————基本梯度是用膨胀后的图像减去腐蚀后的图像得到差值图像,称为梯度图像也是OpenCV中支持的计算形态学梯度的方法,而此方法得到梯度有被称为基本梯度。
内部梯度
————是用原图像减去腐蚀之后的图像得到差值图像,称为图像的内部梯度。
外部梯度
————是用图像膨胀之后再减去原来的图像得到的差值图像,称为图像的外部梯度。
方向梯度
————方向梯度是使用X方向与Y方向的直线作为结构元素之后得到图像梯度,用X方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为X方向梯度,用Y方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为Y方向梯度。

代码如下:仅考虑基本梯度

#include "pch.h"
#include 
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

void CallBack_Size(int pos, void* userdata);

int main()
{
	Mat src = imread("F:\\visual studio\\Image\\src.jpg");
	if (src.empty())
	{
		cout << "Can't load the image" << endl;
		return -1;
	}
	imshow("src", src);
	int elementSize = 0;
	int maxSize = 21;
	createTrackbar("Size", "src", &elementSize, maxSize, CallBack_Size, (void*)&src);
	waitKey(0);
}

void CallBack_Size(int pos,void* userdata)
{
	Mat src = *((Mat*)userdata);
	int size = 2 * pos + 1;
	Mat dst;
	Mat structureElement = getStructuringElement(MORPH_RECT, Size(size, size), Point(-1, -1));
	//morphologyEx(src, dst, MORPH_OPEN, structureElement, Point(-1, -1));
	//morphologyEx(src, dst, MORPH_CLOSE, structureElement, Point(-1, -1));
	morphologyEx(src, dst, MORPH_GRADIENT, structureElement, Point(-1, -1));
	imshow("src", dst);

}

效果如下:

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第8张图片
 

顶帽 是原图像与开操作之间的差值图像:

顶帽变换的定义是原图像减去开运算结果,开运算可以消除暗背景下的较亮区域(一般是较小的区域),那么如果用原图减去开运算结果就可以得到这些原图中灰度较亮的区域。


#include "pch.h"
#include 
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

void CallBack_Size(int pos, void* userdata);

int main()
{
	Mat src = imread("F:\\visual studio\\Image\\src.jpg");
	if (src.empty())
	{
		cout << "Can't load the image" << endl;
		return -1;
	}
	imshow("src", src);
	int elementSize = 0;
	int maxSize = 21;
	createTrackbar("Size", "src", &elementSize, maxSize, CallBack_Size, (void*)&src);
	waitKey(0);
}

void CallBack_Size(int pos,void* userdata)
{
	Mat src = *((Mat*)userdata);
	int size = 2 * pos + 1;
	Mat dst;
	Mat structureElement = getStructuringElement(MORPH_RECT, Size(size, size), Point(-1, -1));
	//morphologyEx(src, dst, MORPH_OPEN, structureElement, Point(-1, -1));
	//morphologyEx(src, dst, MORPH_CLOSE, structureElement, Point(-1, -1));
	//morphologyEx(src, dst, MORPH_GRADIENT, structureElement, Point(-1, -1));
	morphologyEx(src, dst, MORPH_TOPHAT, structureElement, Point(-1, -1));
	imshow("src", dst);

}

效果如下:

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第9张图片

 

黑帽是闭操作图像与源图像的差值图像

底帽变换的定义是闭操作图像与源图像的差值图像,闭运算可以删除亮度较高背景下的较暗区域,那么用闭运算结果减去源图像就可以得到原图像中灰度较暗的区域,所以又称黑底帽变换。

#include "pch.h"
#include 
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

void CallBack_Size(int pos, void* userdata);

int main()
{
	Mat src = imread("F:\\visual studio\\Image\\src.jpg");
	if (src.empty())
	{
		cout << "Can't load the image" << endl;
		return -1;
	}
	imshow("src", src);
	int elementSize = 0;
	int maxSize = 21;
	createTrackbar("Size", "src", &elementSize, maxSize, CallBack_Size, (void*)&src);
	waitKey(0);
}

void CallBack_Size(int pos,void* userdata)
{
	Mat src = *((Mat*)userdata);
	int size = 2 * pos + 1;
	Mat dst;
	Mat structureElement = getStructuringElement(MORPH_RECT, Size(size, size), Point(-1, -1));
	//morphologyEx(src, dst, MORPH_OPEN, structureElement, Point(-1, -1));
	//morphologyEx(src, dst, MORPH_CLOSE, structureElement, Point(-1, -1));
	//morphologyEx(src, dst, MORPH_GRADIENT, structureElement, Point(-1, -1));
	//morphologyEx(src, dst, MORPH_TOPHAT, structureElement, Point(-1, -1));
	morphologyEx(src, dst, MORPH_BLACKHAT, structureElement, Point(-1, -1));
	imshow("src", dst);

}

效果如下:

花老湿OpenCV学习:形态学操作(开、闭运算,形态学梯度,顶帽,黑帽)_第10张图片

总结:

形态学处理往往是在阈值处理以后才进行的,因为当图像被转化为二值图以后,这个时候只有黑白两者颜色,然后再进行形态学处理是效果最好的。

你可能感兴趣的:(OpenCV学习)