zoukankan      html  css  js  c++  java
  • opencv2 学习第8天 提取分离前景和背景

    http://blog.csdn.net/zhouzhouzf/article/details/9281327

    GrabCut

    代码来自于http://www.cnblogs.com/tornadomeet/archive/2012/11/09/2763271.html

    [cpp] view plain copy
     
    1. #include <opencv2/highgui/highgui.hpp>  
    2. #include <opencv2/core/core.hpp>  
    3. #include <vector>  
    4. #include <iostream>  
    5. #include <opencv2/imgproc/imgproc.hpp>  
    6. //#include "../../../../../Downloads/colourhistogram.h"  
    7. using namespace std;  
    8. using namespace cv;  
    9. static void help()  
    10. {  
    11.     cout << " This program demonstrates GrabCut segmentation -- select an object in a region "  
    12.         "and then grabcut will attempt to segment it out. "  
    13.         "Call: "  
    14.         "./grabcut <image_name> "  
    15.         " Select a rectangular area around the object you want to segment " <<  
    16.         " Hot keys:  "  
    17.         " ESC - quit the program "  
    18.         " r - restore the original image "  
    19.         " n - next iteration "  
    20.         " "  
    21.         " left mouse button - set rectangle "  
    22.         " "  
    23.         " CTRL+left mouse button - set GC_BGD pixels "  
    24.         " SHIFT+left mouse button - set CG_FGD pixels "  
    25.         " "  
    26.         " CTRL+right mouse button - set GC_PR_BGD pixels "  
    27.         " SHIFT+right mouse button - set CG_PR_FGD pixels " << endl;  
    28. }  
    29.   
    30. const Scalar RED = Scalar(0,0,255);  
    31. const Scalar PINK = Scalar(230,130,255);  
    32. const Scalar BLUE = Scalar(255,0,0);  
    33. const Scalar LIGHTBLUE = Scalar(255,255,160);  
    34. const Scalar GREEN = Scalar(0,255,0);  
    35.   
    36. const int BGD_KEY = CV_EVENT_FLAG_CTRLKEY;  //Ctrl键  
    37. const int FGD_KEY = CV_EVENT_FLAG_SHIFTKEY; //Shift键  
    38.   
    39. static void getBinMask( const Mat& comMask, Mat& binMask )  
    40. {  
    41.     if( comMask.empty() || comMask.type()!=CV_8UC1 )  
    42.         CV_Error( CV_StsBadArg, "comMask is empty or has incorrect type (not CV_8UC1)" );  
    43.     if( binMask.empty() || binMask.rows!=comMask.rows || binMask.cols!=comMask.cols )  
    44.         binMask.create( comMask.size(), CV_8UC1 );  
    45.     binMask = comMask & 1;  //得到mask的最低位,实际上是只保留确定的或者有可能的前景点当做mask  
    46. }  
    47.   
    48. class GCApplication  
    49. {  
    50. public:  
    51.     enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 };  
    52.     static const int radius = 2;  
    53.     static const int thickness = -1;  
    54.   
    55.     void reset();  
    56.     void setImageAndWinName( const Mat& _image, const string& _winName );  
    57.     void showImage() const;  
    58.     void mouseClick( int event, int x, int y, int flags, void* param );  
    59.     int nextIter();  
    60.     int getIterCount() const { return iterCount; }  
    61. private:  
    62.     void setRectInMask();  
    63.     void setLblsInMask( int flags, Point p, bool isPr );  
    64.   
    65.     const string* winName;  
    66.     const Mat* image;  
    67.     Mat mask;  
    68.     Mat bgdModel, fgdModel;  
    69.   
    70.     uchar rectState, lblsState, prLblsState;  
    71.     bool isInitialized;  
    72.   
    73.     Rect rect;  
    74.     vector<Point> fgdPxls, bgdPxls, prFgdPxls, prBgdPxls;  
    75.     int iterCount;  
    76. };  
    77.   
    78. /*给类的变量赋值*/  
    79. void GCApplication::reset()  
    80. {  
    81.     if( !mask.empty() )  
    82.         mask.setTo(Scalar::all(GC_BGD));  
    83.     bgdPxls.clear(); fgdPxls.clear();  
    84.     prBgdPxls.clear();  prFgdPxls.clear();  
    85.   
    86.     isInitialized = false;  
    87.     rectState = NOT_SET;    //NOT_SET == 0  
    88.     lblsState = NOT_SET;  
    89.     prLblsState = NOT_SET;  
    90.     iterCount = 0;  
    91. }  
    92.   
    93. /*给类的成员变量赋值而已*/  
    94. void GCApplication::setImageAndWinName( const Mat& _image, const string& _winName  )  
    95. {  
    96.     if( _image.empty() || _winName.empty() )  
    97.         return;  
    98.     image = &_image;  
    99.     winName = &_winName;  
    100.     mask.create( image->size(), CV_8UC1);  
    101.     reset();  
    102. }  
    103.   
    104. /*显示4个点,一个矩形和图像内容,因为后面的步骤很多地方都要用到这个函数,所以单独拿出来*/  
    105. void GCApplication::showImage() const  
    106. {  
    107.     if( image->empty() || winName->empty() )  
    108.         return;  
    109.   
    110.     Mat res;  
    111.     Mat binMask;  
    112.     if( !isInitialized )  
    113.         image->copyTo( res );  
    114.     else  
    115.     {  
    116.         getBinMask( mask, binMask );  
    117.         image->copyTo( res, binMask );  //按照最低位是0还是1来复制,只保留跟前景有关的图像,比如说可能的前景,可能的背景  
    118.     }  
    119.   
    120.     vector<Point>::const_iterator it;  
    121.     /*下面4句代码是将选中的4个点用不同的颜色显示出来*/  
    122.     for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it )  //迭代器可以看成是一个指针  
    123.         circle( res, *it, radius, BLUE, thickness );  
    124.     for( it = fgdPxls.begin(); it != fgdPxls.end(); ++it )  //确定的前景用红色表示  
    125.         circle( res, *it, radius, RED, thickness );  
    126.     for( it = prBgdPxls.begin(); it != prBgdPxls.end(); ++it )  
    127.         circle( res, *it, radius, LIGHTBLUE, thickness );  
    128.     for( it = prFgdPxls.begin(); it != prFgdPxls.end(); ++it )  
    129.         circle( res, *it, radius, PINK, thickness );  
    130.   
    131.     /*画矩形*/  
    132.     if( rectState == IN_PROCESS || rectState == SET )  
    133.         rectangle( res, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2);  
    134.   
    135.     imshow( *winName, res );  
    136. }  
    137.   
    138. /*该步骤完成后,mask图像中rect内部是3,外面全是0*/  
    139. void GCApplication::setRectInMask()  
    140. {  
    141.     assert( !mask.empty() );  
    142.     mask.setTo( GC_BGD );   //GC_BGD == 0  
    143.     rect.x = max(0, rect.x);  
    144.     rect.y = max(0, rect.y);  
    145.     rect.width = min(rect.width, image->cols-rect.x);  
    146.     rect.height = min(rect.height, image->rows-rect.y);  
    147.     (mask(rect)).setTo( Scalar(GC_PR_FGD) );    //GC_PR_FGD == 3,矩形内部,为可能的前景点  
    148. }  
    149.   
    150. void GCApplication::setLblsInMask( int flags, Point p, bool isPr )  
    151. {  
    152.     vector<Point> *bpxls, *fpxls;  
    153.     uchar bvalue, fvalue;  
    154.     if( !isPr ) //确定的点  
    155.     {  
    156.         bpxls = &bgdPxls;  
    157.         fpxls = &fgdPxls;  
    158.         bvalue = GC_BGD;    //0  
    159.         fvalue = GC_FGD;    //1  
    160.     }  
    161.     else    //概率点  
    162.     {  
    163.         bpxls = &prBgdPxls;  
    164.         fpxls = &prFgdPxls;  
    165.         bvalue = GC_PR_BGD; //2  
    166.         fvalue = GC_PR_FGD; //3  
    167.     }  
    168.     if( flags & BGD_KEY )  
    169.     {  
    170.         bpxls->push_back(p);  
    171.         circle( mask, p, radius, bvalue, thickness );   //该点处为2  
    172.     }  
    173.     if( flags & FGD_KEY )  
    174.     {  
    175.         fpxls->push_back(p);  
    176.         circle( mask, p, radius, fvalue, thickness );   //该点处为3  
    177.     }  
    178. }  
    179.   
    180. /*鼠标响应函数,参数flags为CV_EVENT_FLAG的组合*/  
    181. void GCApplication::mouseClick( int event, int x, int y, int flags, void* )  
    182. {  
    183.     // TODO add bad args check  
    184.     switch( event )  
    185.     {  
    186.     case CV_EVENT_LBUTTONDOWN: // set rect or GC_BGD(GC_FGD) labels  
    187.         {  
    188.             bool isb = (flags & BGD_KEY) != 0,  
    189.                 isf = (flags & FGD_KEY) != 0;  
    190.             if( rectState == NOT_SET && !isb && !isf )//只有左键按下时  
    191.             {  
    192.                 rectState = IN_PROCESS; //表示正在画矩形  
    193.                 rect = Rect( x, y, 1, 1 );  
    194.             }  
    195.             if ( (isb || isf) && rectState == SET ) //按下了alt键或者shift键,且画好了矩形,表示正在画前景背景点  
    196.                 lblsState = IN_PROCESS;  
    197.         }  
    198.         break;  
    199.     case CV_EVENT_RBUTTONDOWN: // set GC_PR_BGD(GC_PR_FGD) labels  
    200.         {  
    201.             bool isb = (flags & BGD_KEY) != 0,  
    202.                 isf = (flags & FGD_KEY) != 0;  
    203.             if ( (isb || isf) && rectState == SET ) //正在画可能的前景背景点  
    204.                 prLblsState = IN_PROCESS;  
    205.         }  
    206.         break;  
    207.     case CV_EVENT_LBUTTONUP:  
    208.         if( rectState == IN_PROCESS )  
    209.         {  
    210.             rect = Rect( Point(rect.x, rect.y), Point(x,y) );   //矩形结束  
    211.             rectState = SET;  
    212.             setRectInMask();  
    213.             assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );  
    214.             showImage();  
    215.         }  
    216.         if( lblsState == IN_PROCESS )   //已画了前后景点  
    217.         {  
    218.             setLblsInMask(flags, Point(x,y), false);    //画出前景点  
    219.             lblsState = SET;  
    220.             showImage();  
    221.         }  
    222.         break;  
    223.     case CV_EVENT_RBUTTONUP:  
    224.         if( prLblsState == IN_PROCESS )  
    225.         {  
    226.             setLblsInMask(flags, Point(x,y), true); //画出背景点  
    227.             prLblsState = SET;  
    228.             showImage();  
    229.         }  
    230.         break;  
    231.     case CV_EVENT_MOUSEMOVE:  
    232.         if( rectState == IN_PROCESS )  
    233.         {  
    234.             rect = Rect( Point(rect.x, rect.y), Point(x,y) );  
    235.             assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );  
    236.             showImage();    //不断的显示图片  
    237.         }  
    238.         else if( lblsState == IN_PROCESS )  
    239.         {  
    240.             setLblsInMask(flags, Point(x,y), false);  
    241.             showImage();  
    242.         }  
    243.         else if( prLblsState == IN_PROCESS )  
    244.         {  
    245.             setLblsInMask(flags, Point(x,y), true);  
    246.             showImage();  
    247.         }  
    248.         break;  
    249.     }  
    250. }  
    251.   
    252. /*该函数进行grabcut算法,并且返回算法运行迭代的次数*/  
    253. int GCApplication::nextIter()  
    254. {  
    255.     if( isInitialized )  
    256.         //使用grab算法进行一次迭代,参数2为mask,里面存的mask位是:矩形内部除掉那些可能是背景或者已经确定是背景后的所有的点,且mask同时也为输出  
    257.         //保存的是分割后的前景图像  
    258.         grabCut( *image, mask, rect, bgdModel, fgdModel, 1 );  
    259.     else  
    260.     {  
    261.         if( rectState != SET )  
    262.             return iterCount;  
    263.   
    264.         if( lblsState == SET || prLblsState == SET )  
    265.             grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK );  
    266.         else  
    267.             grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT );  
    268.   
    269.         isInitialized = true;  
    270.     }  
    271.     iterCount++;  
    272.   
    273.     bgdPxls.clear(); fgdPxls.clear();  
    274.     prBgdPxls.clear(); prFgdPxls.clear();  
    275.   
    276.     return iterCount;  
    277. }  
    278.   
    279. GCApplication gcapp;  
    280.   
    281. static void on_mouse( int event, int x, int y, int flags, void* param )  
    282. {  
    283.     gcapp.mouseClick( event, x, y, flags, param );  
    284. }  
    285.   
    286. int main( int argc, char** argv )  
    287. {  
    288.   
    289.     string filename = "D:\images\dog.jpg";  
    290.     Mat image = imread( filename, 1 );  
    291.     if( image.empty() )  
    292.     {  
    293.         cout << "  Durn, couldn't read image filename " << filename << endl;  
    294.         return 1;  
    295.     }  
    296.   
    297.     help();  
    298.   
    299.     const string winName = "image";  
    300.     cvNamedWindow( winName.c_str(), CV_WINDOW_AUTOSIZE );  
    301.     cvSetMouseCallback( winName.c_str(), on_mouse, 0 );  
    302.   
    303.     gcapp.setImageAndWinName( image, winName );  
    304.     gcapp.showImage();  
    305.   
    306.     for(;;)  
    307.     {  
    308.         int c = cvWaitKey(0);  
    309.         switch( (char) c )  
    310.         {  
    311.         case 'x1b':  
    312.             cout << "Exiting ..." << endl;  
    313.             goto exit_main;  
    314.         case 'r':  
    315.             cout << endl;  
    316.             gcapp.reset();  
    317.             gcapp.showImage();  
    318.             break;  
    319.         case 'n':  
    320.             int iterCount = gcapp.getIterCount();  
    321.             cout << "<" << iterCount << "... ";  
    322.             int newIterCount = gcapp.nextIter();  
    323.             if( newIterCount > iterCount )  
    324.             {  
    325.                 gcapp.showImage();  
    326.                 cout << iterCount << ">" << endl;  
    327.             }  
    328.             else  
    329.                 cout << "rect must be determined>" << endl;  
    330.             break;  
    331.         }  
    332.     }  
    333.   
    334. exit_main:  
    335.     cvDestroyWindow( winName.c_str() );  
    336.     return 0;  
    337. }  

    opencv2 书本上给的GrabCut的方法代码,实现起来速度也是不太能够忍受
    [cpp] view plain copy
     
    1. class WatershedSegmenter {  
    2.   
    3. private:  
    4.   
    5.     cv::Mat markers;  
    6.   
    7. public:  
    8.   
    9.     void setMarkers(const cv::Mat& markerImage) {  
    10.   
    11.         // Convert to image of ints  
    12.         markerImage.convertTo(markers,CV_32S);  
    13.     }  
    14.   
    15.     cv::Mat process(const cv::Mat &image) {  
    16.   
    17.         // Apply watershed  
    18.         cv::watershed(image,markers);  
    19.   
    20.         return markers;  
    21.     }  
    22.   
    23.     // Return result in the form of an image  
    24.     cv::Mat getSegmentation() {  
    25.   
    26.         cv::Mat tmp;  
    27.         // all segment with label higher than 255  
    28.         // will be assigned value 255  
    29.         markers.convertTo(tmp,CV_8U);  
    30.   
    31.         return tmp;  
    32.     }  
    33.   
    34.     // Return watershed in the form of an image  
    35.     cv::Mat getWatersheds() {  
    36.   
    37.         cv::Mat tmp;  
    38.         markers.convertTo(tmp,CV_8U,255,255);  
    39.   
    40.         return tmp;  
    41.     }  
    42. };  
    43. int main()  
    44. {  
    45.     using namespace cv;  
    46.     // Open another image  
    47.     Mat image= cv::imread("D:\images\tower.jpg");  
    48.   
    49.     // define bounding rectangle  
    50.     cv::Rect rectangle(50,70,image.cols-150,image.rows-180);  
    51.   
    52.     cv::Mat result; // segmentation result (4 possible values)  
    53.     cv::Mat bgModel,fgModel; // the models (internally used)  
    54.     // GrabCut segmentation  
    55.     cv::grabCut(image,    // input image  
    56.         result,   // segmentation result  
    57.         rectangle,// rectangle containing foreground  
    58.         bgModel,fgModel, // models  
    59.         1,        // number of iterations  
    60.         cv::GC_INIT_WITH_RECT); // use rectangle  
    61.   
    62.     // Get the pixels marked as likely foreground  
    63.     cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);  
    64.     // Generate output image  
    65.     cv::Mat foreground(image.size(),CV_8UC3,cv::Scalar(255,255,255));  
    66.     image.copyTo(foreground,result); // bg pixels not copied  
    67.   
    68.     // draw rectangle on original image  
    69.     cv::rectangle(image, rectangle, cv::Scalar(255,255,255),1);  
    70.     cv::namedWindow("Image");  
    71.     cv::imshow("Image",image);  
    72.   
    73.     // display result  
    74.     cv::namedWindow("Segmented Image");  
    75.     cv::imshow("Segmented Image",foreground);  
    76.   
    77.     // Open another image  
    78.     image= cv::imread("D:\images\tower.jpg");  
    79.   
    80.     // define bounding rectangle  
    81.     cv::Rect rectangle2(10,100,380,180);  
    82.   
    83.     cv::Mat bkgModel,fgrModel; // the models (internally used)  
    84.     // GrabCut segmentation  
    85.     cv::grabCut(image,  // input image  
    86.         result, // segmentation result  
    87.         rectangle2,bkgModel,fgrModel,5,cv::GC_INIT_WITH_RECT);  
    88.     // Get the pixels marked as likely foreground  
    89.     //      cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);  
    90.     result= result&1;  
    91.     foreground.create(image.size(),CV_8UC3);  
    92.     foreground.setTo(cv::Scalar(255,255,255));  
    93.     image.copyTo(foreground,result); // bg pixels not copied  
    94.   
    95.     // draw rectangle on original image  
    96.     cv::rectangle(image, rectangle2, cv::Scalar(255,255,255),1);  
    97.     cv::namedWindow("Image 2");  
    98.     cv::imshow("Image 2",image);  
    99.   
    100.     // display result  
    101.     cv::namedWindow("Foreground objects");  
    102.     cv::imshow("Foreground objects",foreground);  
    103.     waitKey(0);  
    104.     system("pause");  
    105.     return 0;  
    106. }  


     
    0
  • 相关阅读:
    ImageView的属性android:scaleType
    Java容器类List、ArrayList、Vector及map、HashTable、HashMap分别的区别. (转)
    Pro Andorid3第一章:Android平台简介
    Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE
    归纳法(induction)
    dual graph
    Project和编程过程
    维度
    dos
    关于glfrustum与hemicube的真实长度的关系
  • 原文地址:https://www.cnblogs.com/jukan/p/7245075.html
Copyright © 2011-2022 走看看