形态学基本操作

一、腐蚀和膨胀

1、腐蚀膨胀基本概念:

跟卷积操作类似,假设有图像A和结构元素B,结构元素在图像A上移动,其中定义B的中心为锚点,计算B覆盖下A的最大值(膨胀)/最小值(腐蚀)的像素值用来替代锚点的像素,其中B可以是矩形,圆,椭圆等任意形状,需要注意腐蚀膨胀操作的图像只能是二值图

下面由左图变到右图是膨胀,因为左图中的最大像素是白色,然后将白色像素值作为锚点的像素值

下面由左图变到右图是腐蚀,因为左图中的最小值像素是黑色,然后将黑色像素值作为锚点的像素值

2、API介绍

a)getStructuringElement(int shape,Size ksize,point anchor)

表示定义前面提到的结构体元素B,参数shape有(MORPH_RECT/MORPH_CROSS/MORPH_ELLISPSE),参数ksize表示卷积核大小,point anchor默认(-1,-1)表示卷积核的中心为锚点

b)dilate(src,dst,kernel)kernel就是前面的结构体元素

c)erode(src,dst,kernel)kernel就是前面的结构体元素

d)createTrackbar("kernel_size:",OUTPUT_WINDOW,element_size,max_size,CallBack_Demo);参数:滑块的名称,滑块依附窗口的名称,初始化滑块的值,滑块最大值,回调函数

3、实现代码:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat src, dst;
char OUTPUT_WINDOW[] = "output_image";
int element_size = 3;
int max_size = 21;
void CallBack_Demo(int, void*);
int main() {
	src = imread("./lena.jpg");
	if (!src.data){
		printf("Could not load image...");
		return -1;
	}
	namedWindow("input-image", CV_WINDOW_AUTOSIZE);
	imshow("input-image", src);

	namedWindow(OUTPUT_WINDOW, CV_WINDOW_AUTOSIZE);
	//创建一个滑块,可以调节kernel的大小
	//参数:滑块的名称,滑块依附窗口的名称,初始化滑块的值,滑块最大值,回调函数
	createTrackbar("kernel_size:",OUTPUT_WINDOW,&element_size,max_size,CallBack_Demo);
	CallBack_Demo(0, 0);
	waitKey(0);
	return 0;
}
void CallBack_Demo(int, void*) {
	int s = element_size + 1;
	Mat kernel = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1,- 1));
	//dilate(src, dst, kernel, Point(-1, -1));
	erode(src, dst, kernel, Point(-1, -1));
	
	imshow(OUTPUT_WINDOW, dst);
}

 输出效果:

 二、形态学操作

1、形态学操作包括:开操作(open)、闭操作(closed)、形态学梯度(Morphological Gradient)、顶帽(top hat)和黑帽(black hat)

2、API:morphlogyEX(src,dst,CV_MOP_OPEN/CLOSE/GRADIENT/TOPHACK/BALCKHAT,kernel),kernel表示结构元素,最后还有一个默认参数是 int iteration表示迭代次数,默认为1,一般取默认

1、开操作 

 开操作:可以去掉小的对象。原理是先进行腐蚀然后膨胀,选用合适大小的kernel可以腐蚀掉小的对象,然后再膨胀将大对象恢复一下(恢复腐蚀过程中腐蚀掉的部分)

实现代码:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main() {
	Mat src, dst;
	src = imread("../../test1.png");
	if (!src.data){
		printf("Could not load image!");
		return -1;
	}
	namedWindow("input_image", CV_WINDOW_AUTOSIZE);
	imshow("input_image",src);
	char output_title[] = "morphology_demo";
	//定义结构元素
	Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));
	//开操作
	morphologyEx(src, dst, CV_MOP_OPEN, kernel);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, dst);
	waitKey(0);
	return 0;
}

实现效果:

 

2、闭操作 

 闭操作:可以填充小黑洞对象。原理是先进行膨胀然后腐蚀,选用合适大小的kernel膨胀的可以填充黑洞,然后用腐蚀将大对象恢复一下(恢复膨胀过程中变大的部分)

 实现代码:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main() {
	Mat src, dst;
	src = imread("../../小黑洞.png");
	if (!src.data) {
		printf("Could not load image!");
		return -1;
	}
	namedWindow("input_image", CV_WINDOW_AUTOSIZE);
	imshow("input_image", src);
	char output_title[] = "morphology_demo";
	// 定义结构元素
	Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));
	// 闭操作
	morphologyEx(src, dst, CV_MOP_CLOSE, kernel);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, dst);
	waitKey(0);
	return 0;
}

实现效果:

3、形态学梯度

实现代码:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main() {
	Mat src, dst;
	src = imread("../../../lena.jpg");
	if (!src.data) {
		printf("Could not load image!");
		return -1;
	}
	namedWindow("input_image", CV_WINDOW_AUTOSIZE);
	imshow("input_image", src);
	char output_title[] = "morphology_demo";
	//定义结构元素
	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
        //形态学梯度
	morphologyEx(src, dst, CV_MOP_GRADIENT, kernel);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, dst);
	waitKey(0);
	return 0;
}

实现效果:

4、顶帽

顶帽:可以获取开操作前后去掉的小部分

实现代码:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main() {
	Mat src,open_res, dst;
	src = imread("../../test1.png");
	if (!src.data) {
		printf("Could not load image!");
		return -1;
	}
	namedWindow("input_image", CV_WINDOW_AUTOSIZE);
	imshow("input_image", src);
	char output_title[] = "morphology_demo";
	//定义结构元素
	Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));
        //开操作
	morphologyEx(src, open_res, CV_MOP_OPEN, kernel);
        //顶帽
	morphologyEx(src, dst, CV_MOP_TOPHAT, kernel);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow("open_res", open_res);
	imshow(output_title, dst);
	waitKey(0);
	return 0;
}

实现效果:

黑帽:在实际应用中,如果图像有个小黑洞,可以使用闭合操作补全,然后可以使用黑帽来获取该黑洞的大小 

实现代码:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main() {
	Mat src,close_res,dst;
	src = imread("../../小黑洞.png");
	if (!src.data) {
		printf("Could not load image!");
		return -1;
	}
	namedWindow("input_image", CV_WINDOW_AUTOSIZE);
	imshow("input_image", src);
	char output_title[] = "morphology_demo";
	// 定义结构元素
	Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));
	// 闭操作
	morphologyEx(src, close_res, CV_MOP_CLOSE, kernel);
	//黑帽
	morphologyEx(src, dst,CV_MOP_BLACKHAT, kernel);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow("close_res", close_res);
	imshow(output_title, dst);
	waitKey(0);
	return 0;
}

实现效果: 

 

 三、膨胀腐蚀+滑条测试

实现代码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;

Mat g_srcImage, g_dstImage;
int g_nTracbarNumber = 0;// 0表示erode,1表示膨胀dilate
int g_nStructElementSize = 3;
void Process();
void On_TrackbarNumChange(int, void*);
void On_ElementSizeChange(int, void*);
int main() {
	system("color5E");
	g_srcImage = imread("../../../lena.jpg");
	if (!g_srcImage.data) {
		printf("Could not load image...");
		return -1;
	}
	namedWindow("original_image");
	imshow("original_image", g_srcImage);
	namedWindow("dst_image");
	 // 创建轨迹条
	createTrackbar("erode/dilate", "dst_image", &g_nTracbarNumber, 1, On_TrackbarNumChange);
	createTrackbar("kernel_size", "dst_image", &g_nStructElementSize, 21, On_ElementSizeChange);
	cout << "程序运行成功~\n"
		<< "按下q退出程序"
		<< endl;
	while (char(waitKey(1)) != 'q') {}
	return 0;
}
void Process() {
	Mat element = getStructuringElement(MORPH_RECT, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize+1), Point(-1, -1));
	if (g_nTracbarNumber == 0) {
		erode(g_srcImage, g_dstImage, element);
	}
	else {
		dilate(g_srcImage, g_dstImage, element);
	}
	imshow("dst_image", g_dstImage);
}
void On_TrackbarNumChange(int, void*) {
	Process();
}
void On_ElementSizeChange(int, void*) {
	Process();
}

实现效果:

 

更多详细介绍可以参考:https://blog.csdn.net/poem_qianmo/article/details/23710721 

The end.

猜你喜欢

转载自blog.csdn.net/Li_haiyu/article/details/86536256
今日推荐