Grabcut
Code from http://www.cnblogs.com/tornadomeet/archive/2012/11/09/2763271.html
# Include <opencv2/highgui. HPP> # include <opencv2/CORE/core. HPP> # include <vector> # include <iostream> # include <opencv2/imgproc. HPP> // # include ".. /.. /.. /.. /.. /downloads/colourhistogram. H "using namespace STD; using namespace CV; static void help () {cout <"\ nthis program demonstrates grabcut segmentation -- select an object in a region \ n" "And then grabcut will attempt to segment it out. \ n" "Call: \ n "". /grabcut <image_name> \ n "\ nselect a rectangular area around the object you want to segment \ n" <"\ nhot keys: \ n "" \ tesc-quit the program \ n "" \ tr-restore the original image \ n "" \ Tn-Next iteration \ n "" \ n "" \ tleft mouse button-set rectangle \ n "" \ n "" \ tctrl + left mouse button-set gc_bgd pixels \ n "" \ tshift + left mouse button-set cg_fgd pixels \ n" "\ n" "\ tctrl + right mouse button-set gc_pr_bg D pixels \ n "\ tshift + right mouse button-set cg_pr_fgd pixels \ n" <Endl;} const scalar Red = scalar (255 ); const scalar pink = scalar (230,130,255); const scalar Blue = scalar (255,255,160, 0); const scalar lightblue = scalar (0,255); const scalar Green = scalar (, 0 ); const int bgd_key = cv_event_flag_ctrlkey; // ctrl key const int fgd_key = cv_event_flag_shiftkey; // Shift key static void getbinmask (const m At & commask, mat & binmask) {If (commask. Empty () | commask. Type ()! = Cv_8uc1) cv_error (cv_stsbadarg, "commask is empty or has incorrect type (not cv_8uc1)"); If (binmask. Empty () | binmask. rows! = Commask. Rows | binmask. Cols! = Commask. cols) binmask. create (commask. size (), cv_8uc1); binmask = commask & 1; // obtain the signature bit of the mask. In fact, only definite or possible foreground points are retained as mask} class gcapplication {public: enum {not_set = 0, in_process = 1, set = 2}; static const int radius = 2; static const int Thickness =-1; void reset (); void setimageandwinname (const mat & _ image, const string & _ winname); void showimage () const; void mouseclick (INT event, int X, int y, int Flags, void * PARAM); int nextiter (); int getitercount () const {return itercount;} PRIVATE: void setrectinmask (); void setlblsinmask (INT flags, point P, bool ispr); const string * winname; const mat * image; MAT mask; MAT bgdmodel, fgdmodel; uchar rectstate, lblsstate, prlblsstate; bool isinitialized; rect; vector <point> fgdpxls, bgdpxls, prfgdpxls, prbgdpxls; int itercount ;};/* assign a value to the class variable */void gcapplicati On: reset () {If (! Mask. empty () mask. setto (scalar: All (gc_bgd); bgdpxls. clear (); fgdpxls. clear (); prbgdpxls. clear (); prfgdpxls. clear (); isinitialized = false; rectstate = not_set; // not_set = 0 lblsstate = not_set; prlblsstate = not_set; itercount = 0 ;} /* assign values to the member variables of the class */void gcapplication: setimageandwinname (const mat & _ image, const string & _ winname) {If (_ image. empty () | _ winname. empty () return; image = & _ image; winname = & _ Winname; mask. create (image-> size (), cv_8uc1); reset () ;}/ * displays four vertices, a rectangle and image content, this function is used in many subsequent steps, so it is used separately */void gcapplication: showimage () const {If (image-> Empty () | winname-> Empty () return; MAT res; MAT binmask; If (! Isinitialized) image-> copyto (RES); else {getbinmask (mask, binmask); image-> copyto (Res, binmask); // copy data based on whether the Delimiter is 0 or 1, only images related to the foreground, such as the possible foreground and possible background} vector <point >:: const_iterator it; /* the following code shows the four selected points in different colors */For (IT = bgdpxls. begin (); it! = Bgdpxls. end (); ++ it) // iterator can be seen as a pointer circle (Res, * It, radius, Blue, thickness); For (IT = fgdpxls. begin (); it! = Fgdpxls. end (); ++ it) // The specified foreground uses red to represent circle (Res, * It, radius, Red, thickness); For (IT = prbgdpxls. begin (); it! = Prbgdpxls. End (); ++ it) circle (Res, * It, radius, lightblue, thickness); For (IT = prfgdpxls. Begin (); it! = Prfgdpxls. end (); ++ it) circle (Res, * It, radius, pink, thickness ); /* draw a rectangle */If (rectstate = in_process | rectstate = set) rectangle (Res, point (rect. x, rect. y), point (rect. X + rect. width, rect. Y + rect. height), Green, 2); imshow (* winname, Res);}/* after this step is completed, the rect inside the mask image is 3, and the outside is all 0 */void gcapplication:: setrectinmask () {assert (! Mask. empty (); mask. setto (gc_bgd); // gc_bgd = 0rect. X = max (0, rect. x); rect. y = max (0, rect. y); rect. width = min (rect. width, image-> cols-rect.x); rect. height = min (rect. height, image-> rows-rect.y); (mask (rect )). setto (scalar (gc_pr_fgd); // gc_pr_fgd = 3, inside the rectangle, possible foreground point} void gcapplication: setlblsinmask (INT flags, point P, bool ispr) {vector <point> * bpxls, * fpxls; uchar bvalue, fvalue; If (! Ispr) // The specified vertex {bpxls = & bgdpxls; fpxls = & fgdpxls; bvalue = gc_bgd; // 0 fvalue = gc_fgd; // 1} else // probability point {bpxls = & prbgdpxls; fpxls = & prfgdpxls; bvalue = gc_pr_bgd; // 2 fvalue = gc_pr_fgd; // 3} If (flags & bgd_key) {bpxls-> push_back (p); Circle (mask, P, radius, bvalue, thickness ); // This point is 2} If (flags & fgd_key) {fpxls-> push_back (p); Circle (mask, P, radius, fvalue, thickness ); // 3}/* mouse response function at this point. The flags parameter is cv_eve. Combination of nt_flag */void gcapplication: mouseclick (INT event, int X, int y, int flags, void *) {// todo Add bad ARGs checkswitch (Event) {Case cv_event_lbuttondown: // set rect or gc_bgd (gc_fgd) Labels {bool ISB = (flags & bgd_key )! = 0, ISF = (flags & fgd_key )! = 0; If (rectstate = not_set &&! ISB &&! ISF) // only when the left button is pressed {rectstate = in_process; // indicates that a rectangle is being painted rect = rect (X, Y, 1, 1 );} if (ISB | ISF) & rectstate = set) // press the alt or shift key and draw a rectangle, indicates that the foreground background is being painted. lblsstate = in_process;} break; Case cv_event_rbuttondown: // set gc_pr_bgd (gc_pr_fgd) Labels {bool ISB = (flags & bgd_key )! = 0, ISF = (flags & fgd_key )! = 0; If (ISB | ISF) & rectstate = set) // draws a possible foreground background point prlblsstate = in_process;} break; Case cv_event_lbuttonup: if (rectstate = in_process) {rect = rect (point (rect. x, rect. y), point (x, y); // rectstate = set at the end of the rectangle; setrectinmask (); Assert (bgdpxls. empty () & fgdpxls. empty () & prbgdpxls. empty () & prfgdpxls. empty (); showimage ();} If (lblsstate = in_process) // you have drawn the front and back attractions {setlblsinmask (flags, point (X, Y ), False); // draw the foreground vertex lblsstate = set; showimage ();} break; Case cv_event_rbuttonup: If (prlblsstate = in_process) {setlblsinmask (flags, point (X, y), true); // draw the background point prlblsstate = set; showimage ();} break; Case cv_event_mousemove: If (rectstate = in_process) {rect = rect (point (rect. x, rect. y), point (x, y); Assert (bgdpxls. empty () & fgdpxls. empty () & prbgdpxls. empty () & prfgdpxls. empty (); showimage (); // constant Display image} else if (lblsstate = in_process) {setlblsinmask (flags, point (x, y), false); showimage ();} else if (prlblsstate = in_process) {setlblsinmask (flags, point (x, y), true); showimage ();} break ;}/ * This function implements the grabcut algorithm, and return the number of iterations of the algorithm operation */INT gcapplication: nextiter () {If (isinitialized) // use grab Algorithm for one iteration. Parameter 2 is mask, the mask bit in it is: Remove all vertices inside the rectangle that may be the background or have been determined as the background, and the mask also saves the split foreground image grabcut (* image, mask, rect, bgdmodel, Fgdmodel, 1); else {If (rectstate! = Set) return itercount; If (lblsstate = set | prlblsstate = set) grabcut (* image, mask, rect, bgdmodel, fgdmodel, 1, gc_init_with_mask ); elsegrabcut (* image, mask, rect, bgdmodel, fgdmodel, 1, gc_init_with_rect); isinitialized = true;} itercount ++; bgdpxls. clear (); fgdpxls. clear (); prbgdpxls. clear (); prfgdpxls. clear (); Return itercount;} gcapplication gcapp; static void on_mouse (INT event, int X, int y, int flags, void * PARAM) {gcapp. mouseclick (event, X, Y, flags, Param);} int main (INT argc, char ** argv) {string filename = "D: \ images \ dog.jpg "; mat image = imread (filename, 1); If (image. empty () {cout <"\ n durn, couldn't read image filename" <FILENAME <Endl; return 1 ;}help (); const string winname = "image"; cvnamedwindow (winname. c_str (), cv_window_autosize); cvsetmousecallback (winname. c_str (), on_mouse, 0); gcapp. setimageandwinname (image, winname); gcapp. showimage (); For (;) {int c = cvwaitkey (0); Switch (char) c) {Case '\ x1b': cout <"exiting... "<Endl; goto exit_main; Case 'r': cout <Endl; gcapp. reset (); gcapp. showimage (); break; Case 'N': int itercount = gcapp. getitercount (); cout <"<" <itercount <"... "; int newitercount = gcapp. nextiter (); If (newitercount> itercount) {gcapp. showimage (); cout <itercount <">" <Endl;} elsecout <"rect must be determined>" <Endl; break ;}} exit_main: cvdestroywindow (winname. c_str (); Return 0 ;}
The grabcut method code provided by opencv2 is not easy to implement.
class WatershedSegmenter {private:cv::Mat markers;public:void setMarkers(const cv::Mat& markerImage) {// Convert to image of intsmarkerImage.convertTo(markers,CV_32S);}cv::Mat process(const cv::Mat &image) {// Apply watershedcv::watershed(image,markers);return markers;}// Return result in the form of an imagecv::Mat getSegmentation() {cv::Mat tmp;// all segment with label higher than 255// will be assigned value 255markers.convertTo(tmp,CV_8U);return tmp;}// Return watershed in the form of an imagecv::Mat getWatersheds() {cv::Mat tmp;markers.convertTo(tmp,CV_8U,255,255);return tmp;}};int main(){using namespace cv;// Open another imageMat image= cv::imread("D:\\images\\tower.jpg");// define bounding rectanglecv::Rect rectangle(50,70,image.cols-150,image.rows-180);cv::Mat result; // segmentation result (4 possible values)cv::Mat bgModel,fgModel; // the models (internally used)// GrabCut segmentationcv::grabCut(image, // input imageresult, // segmentation resultrectangle,// rectangle containing foregroundbgModel,fgModel, // models1, // number of iterationscv::GC_INIT_WITH_RECT); // use rectangle// Get the pixels marked as likely foregroundcv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);// Generate output imagecv::Mat foreground(image.size(),CV_8UC3,cv::Scalar(255,255,255));image.copyTo(foreground,result); // bg pixels not copied// draw rectangle on original imagecv::rectangle(image, rectangle, cv::Scalar(255,255,255),1);cv::namedWindow("Image");cv::imshow("Image",image);// display resultcv::namedWindow("Segmented Image");cv::imshow("Segmented Image",foreground);// Open another imageimage= cv::imread("D:\\images\\tower.jpg");// define bounding rectanglecv::Rect rectangle2(10,100,380,180);cv::Mat bkgModel,fgrModel; // the models (internally used)// GrabCut segmentationcv::grabCut(image, // input imageresult, // segmentation resultrectangle2,bkgModel,fgrModel,5,cv::GC_INIT_WITH_RECT);// Get the pixels marked as likely foreground// cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);result= result&1;foreground.create(image.size(),CV_8UC3);foreground.setTo(cv::Scalar(255,255,255));image.copyTo(foreground,result); // bg pixels not copied// draw rectangle on original imagecv::rectangle(image, rectangle2, cv::Scalar(255,255,255),1);cv::namedWindow("Image 2");cv::imshow("Image 2",image);// display resultcv::namedWindow("Foreground objects");cv::imshow("Foreground objects",foreground);waitKey(0);system("pause");return 0;}