#include<opencv2/opencv.hpp> bool selectObject = false; cv::Point origin; cv::Rect selection; cv::Mat src; cv::Mat srcMarks; cv::Mat result; cv::Mat foreground; void GrabCutSegment(); void onMouse(int event, int x, int y, int, void*) { if (selectObject) { selection.x = MIN(x, origin.x); selection.y = MIN(y, origin.y); selection.width = std::abs(x - origin.x); selection.height = std::abs(y - origin.y); selection &= cv::Rect(0, 0, src.cols, src.rows); } switch (event) { case cv::EVENT_LBUTTONDOWN: origin = cv::Point(x, y); selection = cv::Rect(x, y, 0, 0); selectObject = true; break; case cv::EVENT_LBUTTONDOWN && cv::EVENT_MOUSEMOVE: src.copyTo(srcMarks); cv::rectangle(srcMarks, selection, cv::Scalar(255, 0, 0)); imshow("srcMarks", srcMarks); break; case cv::EVENT_LBUTTONUP: selectObject = false; if (selection.width != 0 && selection.height != 0){ GrabCutSegment(); } break; } } void GrabCutSegment(){ cv::Mat bgModel, fgModel; cv::grabCut(src, result, selection, bgModel, fgModel, 5, cv::GC_INIT_WITH_RECT); cv::compare(result, cv::GC_PR_FGD, result, cv::CMP_EQ); // Generate output image foreground = cv::Mat::ones(src.size(), CV_8UC3); src.copyTo(foreground, result); // bg pixels not copied cv::imshow("segment", foreground); } int main(){ src = cv::imread("hand.jpg"); cv::imshow("src", src); cv::namedWindow("srcMarks"); src.copyTo(srcMarks); cv::setMouseCallback("srcMarks", onMouse, 0); cv::imshow("srcMarks", srcMarks); cv::waitKey(); }
可以使用鼠标在srcMarks窗口中画出前景图像所在矩形,随后使用grabCut函数更加精准的确定每个像素是否属于前景,最后在segment窗口中显示前景图像。
测试图片:
测试结果: