【OpenCV學習筆記】三十二、分水嶺算法及圖像修補

分水嶺算法及圖像修補

1.分水嶺算法——watershed()

2.圖像修補——inpaint()

先上ppt:










代碼:1.分水嶺算法

///分水嶺算法
#include "opencv2/opencv.hpp"
using namespace cv;
int main()
{
	Mat srcImg = imread("bird.jpg",CV_LOAD_IMAGE_COLOR);
	imshow("srcImg", srcImg);
	Mat copyImg = srcImg.clone();
	//1.定義標記圖像markers
	Mat markers(srcImg.size(),CV_8UC1,Scalar(0));
	//標記背景
	rectangle(markers,Point(1,1),Point(srcImg.cols-2,srcImg.rows-2),Scalar(255),1,8);
	//標記鳥
	rectangle(markers, Point(srcImg.cols / 2 - 20, srcImg.rows / 2 - 20), Point(srcImg.cols / 2 +20, srcImg.rows / 2 + 20), Scalar(128), -1, 8);
	//標記石頭
	rectangle(markers, Point(srcImg.cols / 2 - 30, srcImg.rows - 50), Point(srcImg.cols / 2 + 60, srcImg.rows - 10), Scalar(64), -1, 8);
	imshow("markers-input",markers);
	//2.基於標記圖像的分水嶺算法
	//將markers轉換成32位單通道圖像(分水嶺函數要求)
	markers.convertTo(markers,CV_32S);
	//分水嶺算法
	watershed(srcImg,markers);
	//將markers轉換成8位單通道
	markers.convertTo(markers, CV_8UC1);
	imshow("markers-output", markers);
	//3.提取輪廓並繪製輪廓
	Mat mark1, mark2,mark3;
	mark1 = markers.clone();//提取鳥的輪廓
	mark2 = markers.clone();//提取石頭輪廓
	mark3 = markers.clone();//提取背景輪廓
	//閾值化,黑中找白,找鳥
	threshold(mark1,mark1,129,255,CV_THRESH_TOZERO_INV);
	threshold(mark1,mark1,120,255,CV_THRESH_TOZERO);
	//閾值化,黑中找白,找石頭
	threshold(mark2, mark2, 65, 255, CV_THRESH_TOZERO_INV);
	//閾值化,黑中找白,找背景
	threshold(mark3, mark3, 129, 255, CV_THRESH_BINARY);
	imshow("mark1", mark1);
	imshow("mark2", mark2);
	imshow("mark3", mark3);
	//尋找背景輪廓並繪製
	vector<vector<Point>> contours3;
	findContours(mark3, contours3, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
	drawContours(copyImg, contours3, -1, Scalar(0, 0, 255), -1, 8);
	//尋找鳥輪廓並繪製
	vector<vector<Point>> contours1;
	findContours(mark1,contours1,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
	drawContours(copyImg,contours1,-1,Scalar(255,0,0),-1,8);
	//尋找石頭輪廓並繪製
	vector<vector<Point>> contours2;
	findContours(mark2, contours2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
	drawContours(copyImg, contours2, -1, Scalar(0, 255, 0), -1, 8);
	imshow("copyImg",copyImg);
	//4.與原圖像疊加
	Mat result = srcImg*0.5 + copyImg*0.5;
	imshow("result", result);
	waitKey(0);
	return 0;
}

運行結果:





代碼:2.圖像修補

///圖像修補
#include "opencv2/opencv.hpp"
using namespace cv;
//定義原圖像srcImg和目標圖像dstImg
Mat srcImg = imread("face.JPG", CV_LOAD_IMAGE_COLOR);
Mat dstImg = srcImg.clone();
//定義掩碼inpaintMask,同srcImg一樣大小,類型爲8位單通道,初始化爲純黑(掩碼非0部分起作用)
Mat inpaintMask(srcImg.size(), CV_8UC1, Scalar(0));
//定義鼠標左鍵是否按下的標誌flag
bool flag=false;
//記錄鼠標左鍵按下時的初始座標
int xStart, yStart;
void onMouse(int event,int x,int y,int flags,void* param)
{
	switch (event)
	{
	case CV_EVENT_LBUTTONDOWN:
		flag = true;//鼠標左鍵按下,flag置爲true
		xStart = x;//記錄鼠標左鍵按下時的座標
		yStart = y;
		break;
	case CV_EVENT_MOUSEMOVE:
		if (flag)
		{
			//在srcImg中畫矩形,白色,向內填充
			rectangle(srcImg, Point(xStart, yStart), Point(x, y), Scalar(255, 255, 255), -1, 8);
			//在inpaintMask中畫矩形,白色,向內填充
			rectangle(inpaintMask, Point(xStart, yStart), Point(x, y), Scalar(255, 255, 255), -1, 8);
		}
		break;
	case CV_EVENT_LBUTTONUP:
		flag = false;//鼠標左鍵擡起,flag置爲false
		break;
	default:
		break;
	}
	//重新顯示原圖srcImg
	imshow("inpaint", srcImg);
	//重新顯示掩碼圖像inpaintMask
	imshow("inpaintMask", inpaintMask);
}

int main()
{	
	imshow("srcImg", srcImg);
	//定義窗口"inpaint"
	namedWindow("inpaint",CV_WINDOW_AUTOSIZE);
	//設置鼠標回調函數
	setMouseCallback("inpaint",onMouse);
	//使得一開始就顯示窗口"inpaint",顯示原圖srcImg
	imshow("inpaint", srcImg);
	//使得一開始就顯示窗口"inpaintMask",顯示掩碼圖像inpaintMask
	imshow("inpaintMask", inpaintMask);
	//使得一開始就顯示窗口"dstImg",顯示目標圖像dstImg
	imshow("dstImg", dstImg);
	//無限循環,若按下空格鍵(ASCII碼爲32),則調用inpait()函數,重新顯示目標圖像dstImg
	while (1)
	{
		if (waitKey(0) == 32)//若按下空格鍵
		{
			//調用inpait()函數, 重新顯示目標圖像dstImg
			inpaint(srcImg, inpaintMask, dstImg, 4, CV_INPAINT_NS);
			imshow("dstImg", dstImg);
		}
	}
	waitKey(0);
	return 0;
}

運行結果:





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章