引言
Grab Cut是在Graph Cut上进行改进的,相比后者,前者的新颖之处在于:
- 迭代预测估计(iterative estimation)
- 不完全标记(incomplete labelling)
用户可以通过较少的交互性标记,就可以完成图像分割。具体的原理参考以下文章:
文中提到的经典论文:
- Interactive Graph Cutsfor Optimal Boundary & Region Segmentation of Objects in N-D Images (Yuri Y. Boykov Marie-Pierre Jolly)
- “GrabCut” — Interactive Foreground Extraction using Iterated Graph Cuts (Carsten Rother Vladimir Kolmogorov
Andrew Blake)
代码
最近在看图像分割方面的论文,发现了这种分割方法,这里复现了《“GrabCut” — Interactive Foreground Extraction using Iterated Graph Cuts》中的图像分割。只需要用鼠标将目标框出,可以将目标图像从复杂背景中“扣”出来。
// ConvertColor.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
// Global variables
// Flags updated according to left mouse button activity
bool ldown = false, lup = false;
// Original image
Mat img;
// Starting and ending points of the user's selection
Point corner1, corner2;
// ROI
Rect box;
Mat bgModel, fgModel, mask;
// Callback function for mouse events
static void mouse_callback(int event, int x, int y, int, void *)
{
// When the left mouse button is pressed, record its position and save it in corner1
if (event == EVENT_LBUTTONDOWN)
{
ldown = true;
corner1.x = x;
corner1.y = y;
cout << "Corner 1 recorded at " << corner1 << endl;
}
// When the left mouse button is released, record its position and save it in corner2
if (event == EVENT_LBUTTONUP)
{
// Also check if user selection is bigger than 20 pixels (jut for fun!)
if (abs(x - corner1.x) > 10 && abs(y - corner1.y) > 10)
{
lup = true;
ldown = false;
corner2.x = x;
corner2.y = y;
cout << "Corner 2 recorded at " << corner2 << endl << endl;
}
else
{
cout << "Please select a bigger region" << endl;
ldown = false;
}
}
// Update the box showing the selected region as the user drags the mouse
if (ldown == true && lup == false)
{
Point pt;
pt.x = x;
pt.y = y;
Mat local_img = img.clone();
rectangle(local_img, corner1, pt, Scalar(0, 0, 255),3);
imshow("Cropping app", local_img);
}
// Define ROI and crop it out when both corners have been selected
if (ldown == false && lup == true)
{
box.width = abs(corner1.x - corner2.x);
box.height = abs(corner1.y - corner2.y);
box.x = min(corner1.x, corner2.x);
box.y = min(corner1.y, corner2.y);
// Make an image out of just the selected ROI and display it in a new window
/* Mat crop(img, box);*/
grabCut(img, mask, box, bgModel, fgModel, 5, cv::GC_INIT_WITH_RECT);
compare(mask, GC_PR_FGD, mask, cv::CMP_EQ);
namedWindow("Crop");
Mat imageROI;
imageROI.create(img.size(), img.type());
/*imageROI = img(Rect(box));*/
imageROI.setTo(Scalar(255, 255, 255));
img.copyTo(imageROI, mask);
Mat crop(imageROI, box);
imshow("Crop", crop);
//Mat test = img - imageROI;
//imshow("Crop", test);
///*imwrite("Crop1.jpg", imageROI);*/
ldown = false;
lup = false;
}
}
int main()
{
img = imread("flower.jpg");
/*img = imread("Crop.jpg");*/
namedWindow("Cropping app");
imshow("Cropping app", img);
// Set the mouse event callback function
setMouseCallback("Cropping app", mouse_callback);
// Exit by pressing 'q'
while (char(waitKey(1)) != 'q') {}
return 0;
}
结果
从下图看,效果还算可以!