本篇文章為大家展示了OpenCV的GrabCut可運(yùn)行代碼及實(shí)例,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
公司主營業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)建站推出阿拉善盟免費(fèi)做網(wǎng)站回饋大家。
OpenCV中 GrabCut 的可運(yùn)行代碼
參考:http://www.cnblogs.com/tornadomeet/archive/2012/11/09/2763271.html
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #includeusing 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 \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_BGD pixels\n" "\tSHIFT+right mouse button - set CG_PR_FGD pixels\n" << endl; } const Scalar RED = Scalar(0,0,255); const Scalar PINK = Scalar(230,130,255); const Scalar BLUE = Scalar(255,0,0); const Scalar LIGHTBLUE = Scalar(255,255,160); const Scalar GREEN = Scalar(0,255,0); const int BGD_KEY = CV_EVENT_FLAG_CTRLKEY; //Ctrl鍵 const int FGD_KEY = CV_EVENT_FLAG_SHIFTKEY; //Shift鍵 static void getBinMask( const Mat& 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; //得到mask的最低位,實(shí)際上是只保留確定的或者有可能的前景點(diǎn)當(dāng)做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 rect; vector fgdPxls, bgdPxls, prFgdPxls, prBgdPxls; int iterCount; }; /*給類的變量賦值*/ void GCApplication::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; } /*給類的成員變量賦值而已*/ 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(); } /*顯示4個(gè)點(diǎn),一個(gè)矩形和圖像內(nèi)容,因?yàn)楹竺娴牟襟E很多地方都要用到這個(gè)函數(shù),所以單獨(dú)拿出來*/ 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 ); //按照最低位是0還是1來復(fù)制,只保留跟前景有關(guān)的圖像,比如說可能的前景,可能的背景 } vector ::const_iterator it; /*下面4句代碼是將選中的4個(gè)點(diǎn)用不同的顏色顯示出來*/ for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it ) //迭代器可以看成是一個(gè)指針 circle( res, *it, radius, BLUE, thickness ); for( it = fgdPxls.begin(); it != fgdPxls.end(); ++it ) //確定的前景用紅色表示 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 ); /*畫矩形*/ 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 ); } /*該步驟完成后,mask圖像中rect內(nèi)部是3,外面全是0*/ void GCApplication::setRectInMask() { assert( !mask.empty() ); mask.setTo( GC_BGD ); //GC_BGD == 0 rect.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,矩形內(nèi)部,為可能的前景點(diǎn) } void GCApplication::setLblsInMask( int flags, Point p, bool isPr ) { vector *bpxls, *fpxls; uchar bvalue, fvalue; if( !isPr ) //確定的點(diǎn) { bpxls = &bgdPxls; fpxls = &fgdPxls; bvalue = GC_BGD; //0 fvalue = GC_FGD; //1 } else //概率點(diǎn) { 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 ); //該點(diǎn)處為2 } if( flags & FGD_KEY ) { fpxls->push_back(p); circle( mask, p, radius, fvalue, thickness ); //該點(diǎn)處為3 } } /*鼠標(biāo)響應(yīng)函數(shù),參數(shù)flags為CV_EVENT_FLAG的組合*/ void GCApplication::mouseClick( int event, int x, int y, int flags, void* ) { // TODO add bad args check switch( 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 )//只有左鍵按下時(shí) { rectState = IN_PROCESS; //表示正在畫矩形 rect = Rect( x, y, 1, 1 ); } if ( (isb || isf) && rectState == SET ) //按下了alt鍵或者shift鍵,且畫好了矩形,表示正在畫前景背景點(diǎn) 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 ) //正在畫可能的前景背景點(diǎn) prLblsState = IN_PROCESS; } break; case CV_EVENT_LBUTTONUP: if( rectState == IN_PROCESS ) { rect = Rect( Point(rect.x, rect.y), Point(x,y) ); //矩形結(jié)束 rectState = SET; setRectInMask(); assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() ); showImage(); } if( lblsState == IN_PROCESS ) //已畫了前后景點(diǎn) { setLblsInMask(flags, Point(x,y), false); //畫出前景點(diǎn) lblsState = SET; showImage(); } break; case CV_EVENT_RBUTTONUP: if( prLblsState == IN_PROCESS ) { setLblsInMask(flags, Point(x,y), true); //畫出背景點(diǎn) 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(); //不斷的顯示圖片 } 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; } } /*該函數(shù)進(jìn)行g(shù)rabcut算法,并且返回算法運(yùn)行迭代的次數(shù)*/ int GCApplication::nextIter() { if( isInitialized ) //使用grab算法進(jìn)行一次迭代,參數(shù)2為mask,里面存的mask位是:矩形內(nèi)部除掉那些可能是背景或者已經(jīng)確定是背景后的所有的點(diǎn),且mask同時(shí)也為輸出 //保存的是分割后的前景圖像 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 ); else grabCut( *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 = "C:\\Users\\ycadai\\Desktop\\9.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; } else cout << "rect must be determined>" << endl; break; } } exit_main: cvDestroyWindow( winName.c_str() ); return 0; }
真的很佩服這個(gè)算法!
運(yùn)行結(jié)果:
A.
上述內(nèi)容就是OpenCV的GrabCut可運(yùn)行代碼及實(shí)例,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。