1. 程式人生 > >openCV學習筆記(二十三) —— 形態學濾波—— 開運算、閉運算、形態學梯度、頂帽、黑帽

openCV學習筆記(二十三) —— 形態學濾波—— 開運算、閉運算、形態學梯度、頂帽、黑帽

原理

 

 

 

程式

#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

/*
	巨集定義
*/
#define ORIGINAL_WINDOW_NAME	"【原始圖】"
#define OPEN_CLOSE_WINDOW_NAME	"【開運算/閉運算】"
#define ERODE_DILATE_WINDOW_NAME	"【腐蝕/膨脹】"
#define TOP_BLACK_HAT_WINDOW_NAME	"【頂帽/黑帽】"
#define GRADIENT_WINDOW_NAME	"形態學梯度"

/*
	全域性變數宣告
*/
Mat g_srcImage, g_dstImage;	//原始圖和效果圖
int g_nElementShape = MORPH_RECT;	//元素結構的形狀

									//變數接收的TrackBar位置引數
int g_nMaxIteratorNum = 10;
int g_nOpenCloseNum = 0;
int g_nErodeDilateNum = 0;
int g_nTopBlackHatNum = 0;
int g_nGradientNum = 0;

/*
	全域性函式宣告
*/
static void onOpenClose(int, void *);
static void onErodeDilate(int, void *);
static void onTopBlackHat(int, void *);
static void onGradient(int, void *);

/*
	main()函式
*/
int main()
{
	//載入原圖
	g_srcImage = imread("test.jpg");
	if (!g_srcImage.data)
	{
		printf("讀取srcImage錯誤!\n");
		return -1;
	}

	//顯示原始圖
	namedWindow(ORIGINAL_WINDOW_NAME);
	imshow(ORIGINAL_WINDOW_NAME, g_srcImage);

	//建立四個視窗
	namedWindow(OPEN_CLOSE_WINDOW_NAME);
	namedWindow(ERODE_DILATE_WINDOW_NAME);
	namedWindow(TOP_BLACK_HAT_WINDOW_NAME);
	namedWindow(GRADIENT_WINDOW_NAME);

	//引數賦值
	g_nOpenCloseNum = 9;
	g_nErodeDilateNum = 9;
	g_nTopBlackHatNum = 2;
	g_nGradientNum = 9;

	//分別為四個視窗建立滾動條
	createTrackbar("迭代值", OPEN_CLOSE_WINDOW_NAME, &g_nOpenCloseNum, g_nMaxIteratorNum * 2 + 1, onOpenClose);
	createTrackbar("迭代值", ERODE_DILATE_WINDOW_NAME, &g_nErodeDilateNum, g_nMaxIteratorNum * 2 + 1, onErodeDilate);
	createTrackbar("迭代值", TOP_BLACK_HAT_WINDOW_NAME, &g_nTopBlackHatNum, g_nMaxIteratorNum * 2 + 1, onTopBlackHat);
	createTrackbar("迭代值", GRADIENT_WINDOW_NAME, &g_nGradientNum, g_nMaxIteratorNum * 2 + 1, onGradient);

	//輪詢獲取按鍵資訊
	while (true)
	{
		int c;

		//執行回撥函式
		onOpenClose(g_nOpenCloseNum, NULL);
		onErodeDilate(g_nErodeDilateNum, NULL);
		onTopBlackHat(g_nTopBlackHatNum, NULL);

		//獲取按鍵
		c = waitKey(0);

		//按下鍵盤按鍵Q或者ESC, 程式退出
		if ((char)c == 'q' || (char)c == 27)
		{
			break;
		}

		//按下鍵盤按鍵1,使用橢圓(Ellipse)結構元素MORPH_ELLIPSE
		if ((char)c == 49)	//鍵盤按鍵1的ASCII碼為49
		{
			printf("使用橢圓結構元素");
			g_nElementShape = MORPH_ELLIPSE;
		}
		//按下鍵盤按鍵2,使用矩形(Rectangle)結構元素MORPH_RECT
		else if ((char)c == 50)	//鍵盤按鍵2的ASCII碼為50
		{
			printf("使用矩形結構元素");
			g_nElementShape = MORPH_RECT;
		}
		//按下鍵盤按鍵3,使用十字形(Cross-shaped)結構元素MORPH_RECT
		else if ((char)c == 51)	//鍵盤按鍵3的ASCII碼為50
		{
			printf("使用十字形結構元素");
			g_nElementShape = MORPH_CROSS;
		}
		//按下鍵盤空格,在矩形、橢圓、十字形結構元素中迴圈
		else if ((char)c == ' ')
		{
			printf("在矩形、橢圓、十字形結構元素中迴圈");
			g_nElementShape = (g_nElementShape + 1) % 3;
		}
	}

	destroyAllWindows();

	return 0;
}

/*
	開運算/閉運算視窗的回撥函式
*/
static void onOpenClose(int, void *)
{
	//偏移量的定義
	int offset = g_nOpenCloseNum - g_nMaxIteratorNum;	//偏移量
	int AbsoluteOffset = offset > 0 ? offset : -offset;	//偏移量絕對值

														//自定義核
	Mat element = getStructuringElement(g_nElementShape, Size(AbsoluteOffset * 2 + 1, AbsoluteOffset * 2 + 1), Point(AbsoluteOffset, AbsoluteOffset));

	//進行操作
	if (offset < 0)
	{
		printf("開運算...\n");
		morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);
	}
	else
	{
		printf("閉運算...\n");
		morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);
	}

	imshow(OPEN_CLOSE_WINDOW_NAME, g_dstImage);
}

/*
腐蝕/膨脹視窗的回撥函式
*/
static void onErodeDilate(int, void *)
{
	//偏移量的定義
	int offset = g_nErodeDilateNum - g_nMaxIteratorNum;	//偏移量
	int AbsoluteOffset = offset > 0 ? offset : -offset;	//偏移量絕對值

														//自定義核
	Mat element = getStructuringElement(g_nElementShape, Size(AbsoluteOffset * 2 + 1, AbsoluteOffset * 2 + 1), Point(AbsoluteOffset, AbsoluteOffset));

	//進行操作
	if (offset < 0)
	{
		printf("腐蝕運算...\n");
		erode(g_srcImage, g_dstImage, element);
	}
	else
	{
		printf("膨脹運算...\n");
		dilate(g_srcImage, g_dstImage, element);
	}

	imshow(ERODE_DILATE_WINDOW_NAME, g_dstImage);
}

/*
頂帽/黑帽視窗的回撥函式
*/
static void onTopBlackHat(int, void *)
{
	//偏移量的定義
	int offset = g_nTopBlackHatNum - g_nMaxIteratorNum;	//偏移量
	int AbsoluteOffset = offset > 0 ? offset : -offset;	//偏移量絕對值

														//自定義核
	Mat element = getStructuringElement(g_nElementShape, Size(AbsoluteOffset * 2 + 1, AbsoluteOffset * 2 + 1), Point(AbsoluteOffset, AbsoluteOffset));

	//進行操作
	if (offset < 0)
	{
		printf("頂帽運算...\n");
		morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);
	}
	else
	{
		printf("黑帽運算...\n");
		morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
	}

	imshow(TOP_BLACK_HAT_WINDOW_NAME, g_dstImage);
}


/*
形態學梯度視窗的回撥函式
*/
static void onGradient(int, void *)
{
	//偏移量的定義
	int offset = g_nGradientNum - g_nMaxIteratorNum;	//偏移量
	int AbsoluteOffset = offset > 0 ? offset : -offset;	//偏移量絕對值

														//自定義核
	Mat element = getStructuringElement(g_nElementShape, Size(AbsoluteOffset * 2 + 1, AbsoluteOffset * 2 + 1), Point(AbsoluteOffset, AbsoluteOffset));

	//進行操作
	printf("形態學梯度運算...\n");
	morphologyEx(g_srcImage, g_dstImage, MORPH_GRADIENT, element);

	imshow(GRADIENT_WINDOW_NAME, g_dstImage);
}