1. 程式人生 > >opencv學習筆記五十八:grabCut摳圖

opencv學習筆記五十八:grabCut摳圖

基本步驟:

  • 基於互動式介面由使用者選擇前景區域;
  • 定義一個單通道的輸出掩碼,0為背景,1為前景,2為可能的背景,3為可能的前景;
  • grabCut摳圖;將輸出結果與可能的前景作比較得到可能的前景;
  • 定義三通道的結果影象;
  • 從原圖中拷貝可能的前景到結果影象;
grabCut( InputArray img, InputOutputArray mask, Rect rect,
                           InputOutputArray bgdModel, InputOutputArray fgdModel,
                           int iterCount, int mode = GC_EVAL );

 img:輸入原影象;

mask:輸出掩碼;

rect:使用者選擇的前景矩形區域;

bgModel:輸出背景影象;

fgModel:輸出前景影象;

iterCount:迭代次數;

#include<opencv2\opencv.hpp>
using namespace cv;
void onMouse(int event, int x, int y, int flags, void* userdata);
Rect rect;
Mat src,roiImg, result;
void showImg();
int main(int arc, char** argv) { 
	src = imread("3.jpg");
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src); 
	setMouseCallback("input", onMouse);
	//定義輸出結果,結果為:GC_BGD =0(背景),GC_FGD =1(前景),GC_PR_BGD = 2(可能的背景), GC_PR_FGD = 3(可能的前景)		
	Mat result = Mat::zeros(src.size(), CV_8UC1);
	// GrabCut 摳圖
	//兩個臨時矩陣變數,作為演算法的中間變數使用
	Mat bgModel, fgModel;
	char c = waitKey(0);
	if (c == 'g') {
		grabCut(src, result, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT);
		//比較result的值為可能的前景畫素才輸出到result中
		compare(result, GC_PR_FGD, result, CMP_EQ);
		// 產生輸出影象
		Mat foreground(src.size(), CV_8UC3, Scalar(255, 255, 255));
		//將原影象src中的result區域拷貝到foreground中
		src.copyTo(foreground, result);
		imshow("output", foreground);
	}
	waitKey(0); 
	return 0;
}


void showImg() {
	src.copyTo(roiImg);
	rectangle(roiImg, rect, Scalar(0, 0, 255), 2);
	imshow("input", roiImg);
}
//滑鼠選擇矩形框
void onMouse(int event, int x, int y, int flags, void* userdata){
	switch (event)
	{
	case CV_EVENT_LBUTTONDOWN://滑鼠左鍵按下事件
		rect.x = x;
		rect.y = y;
		rect.width = 1;
		rect.height = 1;
		break;
	case CV_EVENT_MOUSEMOVE://滑鼠移動事件
		if (flags && CV_EVENT_FLAG_LBUTTON) {
			rect = Rect(Point(rect.x, rect.y), Point(x, y));
			showImg();
		}
		break;
	case EVENT_LBUTTONUP://滑鼠彈起事件
		if (rect.width > 1 && rect.height > 1) {
			showImg();
		}
		break;
	default:
		break;
	}
}