zoukankan      html  css  js  c++  java
  • via OpenCv 提取分离前景和背景

      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( "Lena.jpg", 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     
    336     cvDestroyWindow( winName.c_str() );  
    337     return 0;  
    338 }  
    GrabCut

    设置snake算法使用的参数:
         alpha代表点相互靠拢的权值(0-1.0)
         beta表示弯曲能量(越小越容易弯曲)(0-1.0),
         gamma表示整体能量(0-1.0)

  • 相关阅读:
    python 中关于kafka的API
    python 中对json的操作
    python 错误--UnboundLocalError: local variable '**' referenced before assignment
    storm问题记录(1) python 不断向kafka中写消息,spout做为消费者从kafka中读消息并emit给bolt,但是部分消息没有得到bolt的处理
    nodejs+kafka+storm+hbase 开发
    python构造数据
    Head first java中提到的学习方法,很受用
    【机器学习 第2章 学习笔记】模型评估与选择
    路书
    二分搜索
  • 原文地址:https://www.cnblogs.com/gaohai/p/5788855.html
Copyright © 2011-2022 走看看