graphcut到grabcut

转载请注明出处:http://blog.csdn.net/wangyaninglm/article/details/44151213

来自:shiter编写程序的艺术


 1.绪论

图切割算法是组合图论的经典算法之一。近年来,许多学者将其应用到图像和视频分割中,取得了很好的效果。本文简单介绍了图切算法和交互式图像分割技术,以及图切算法在交互式图像分割中的应用。

 

图像分割指图像分成各具特性的区域并提取出感兴趣目标的技术和过程,它是由图像处理到图像分析的关键步骤,是一种基本的计算机视觉技术。只有在图像分割的基础上才能对目标进行特征提取和参数测量,使得更高层的图像分析和理解成为可能。因此对图像分割方法的研究具有十分重要的意义。

 

图像分割技术的研究已有几十年的历史,但至今人们并不能找到通用的方法能够适合于所有类型的图像。常用的图像分割技术可划分为四类:特征阈值或聚类、边缘检测、区域生长或区域提取。虽然这些方法分割灰度图像效果较好,但用于彩色图像的分割往往达不到理想的效果。

 

交互式图像分割是指,首先由用户以某种交互手段指定图像的部分前景与部分背景,然后算法以用户的输入作为分割的约束条件自动地计算出满足约束条件下的最佳分割。典型的交互手段包括用一把画刷在前景和背景处各画几笔(如[1][4]等)以及在前景的周围画一个方框(如[2])等。

 

基于图切算法的图像分割技术是近年来国际上图像分割领域的一个新的研究热点。该类方法将图像映射为赋权无向图,把像素视作节点,利用最小切割得到图像的最佳分割。


 2.几种改进算法

 

  • Graph Cut[1]算法是一种直接基于图切算法的图像分割技术。它仅需要在前景和背景处各画几笔作为输入,算法将建立各个像素点与前景背景相似度的赋权图,并通过求解最小切割区分前景和背景。

 

  • Grabcut[2]算法方法的用户交互量很少,仅仅需要指定一个包含前景的矩形,随后用基于图切算法在图像中提取前景。

 

  • Lazy Snapping[4]系统则是对[1]的改进。通过预计算和聚类技术,该方法提供了一个即时反馈的平台,方便用户进行交互分割。

 

文档说明:

http://download.csdn.net/detail/wangyaninglm/8484301

 

3.代码实现效果


 

 

 

 

 

graphcuts代码:

http://download.csdn.net/detail/wangyaninglm/8484243

 

 

 

 

ICCV'2001论文"Interactive graph cuts for optimal boundary and region segmentation of objects in N-D images"。

Graph Cut方法是基于颜色统计采样的方法,因此对前背景相差较大的图像效果较佳。

同时,比例系数lambda的调节直接影响到最终的分割效果。

 

 

grabcut代码:

 

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


 lazy snapping代码实现:

 

[cpp]  view plain  copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. // LazySnapping.cpp 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include   
  6. #include   
  7. #include "graph.h"  
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12.   
  13. using namespace std;  
  14.   
  15. typedef Graph<</span>float,float,floatGraphType;  
  16.   
  17. class LasySnapping  
  18.  
  19.       
  20. public  
  21.     LasySnapping();  
  22.   
  23.     ~LasySnapping()  
  24.       
  25.         if(graph)  
  26.          
  27.             delete graph;  
  28.          
  29.     };  
  30. private  
  31.     vector forePts;  
  32.     vector backPts;  
  33.     IplImage* image;  
  34.     // average color of foreground points  
  35.     unsigned char avgForeColor[3];  
  36.     // average color of background points  
  37.     unsigned char avgBackColor[3];  
  38. public  
  39.     void setImage(IplImage* image)  
  40.      
  41.         this->image image;  
  42.         graph new GraphType(image->width*image->height,image->width*image->height*2);  
  43.      
  44.     // include-pen locus  
  45.     void setForegroundPoints(vector pts)  
  46.      
  47.         forePts.clear();  
  48.         for(int =0; i< pts.size(); i++)  
  49.          
  50.             if(!isPtInVector(pts[i],forePts))  
  51.              
  52.                 forePts.push_back(pts[i]);  
  53.              
  54.          
  55.         if(forePts.size() == 0)  
  56.          
  57.             return 
  58.          
  59.         int sum[3] {0};  
  60.         for(int =0; forePts.size(); i++)  
  61.          
  62.             unsigned char(unsigned char*)image->imageData forePts[i].x   
  63.                 forePts[i].y*image->widthStep;  
  64.             sum[0] += p[0];  
  65.             sum[1] += p[1];  
  66.             sum[2] += p[2];              
  67.          
  68.         cout<<sum[0]<<" <<forePts.size()<<endl;  
  69.         avgForeColor[0] sum[0]/forePts.size();  
  70.         avgForeColor[1] sum[1]/forePts.size();  
  71.         avgForeColor[2] sum[2]/forePts.size();  
  72.      
  73.     // exclude-pen locus  
  74.     void setBackgroundPoints(vector pts)  
  75.      
  76.         backPts.clear();  
  77.         for(int =0; i< pts.size(); i++)  
  78.          
  79.             if(!isPtInVector(pts[i],backPts))  
  80.              
  81.                 backPts.push_back(pts[i]);  
  82.              
  83.          
  84.         if(backPts.size() == 0)  
  85.          
  86.             return 
  87.          
  88.         int sum[3] {0};  
  89.         for(int =0; backPts.size(); i++)  
  90.          
  91.             unsigned char(unsigned char*)image->imageData backPts[i].x   
  92.                 backPts[i].y*image->widthStep;  
  93.             sum[0] += p[0];  
  94.             sum[1] += p[1];  
  95.             sum[2] += p[2];              
  96.          
  97.         avgBackColor[0] sum[0]/backPts.size();  
  98.         avgBackColor[1] sum[1]/backPts.size();  
  99.         avgBackColor[2] sum[2]/backPts.size();  
  100.      
  101.   
  102.     // return maxflow of graph  
  103.     int runMaxflow();  
  104.     // get result, grayscale mast image indicating forground by 255 and background by 0  
  105.     IplImage* getImageMask();  
  106.   
  107. private  
  108.   
  109.     float colorDistance(unsigned charcolor1, unsigned charcolor2);  
  110.     float minDistance(unsigned charcolor, vector points);  
  111.     bool isPtInVector(CvPoint pt, vector points);  
  112.     void getE1(unsigned charcolor,floatenergy);  
  113.     float getE2(unsigned charcolor1,unsigned charcolor2);  
  114.       
  115.     GraphType *graph;      
  116. };  
  117.   
  118. LasySnapping::LasySnapping()  
  119.  
  120.     graph NULL;  
  121.     avgForeColor[0] 0;  
  122.     avgForeColor[1] 0;  
  123.     avgForeColor[2] 0;  
  124.   
  125.     avgBackColor[0] 0;  
  126.     avgBackColor[1] 0;  
  127.     avgBackColor[2] 0;  
  128.   
  129.       
  130.  
  131.   
  132.   
  133.   
  134. float LasySnapping::colorDistance(unsigned charcolor1, unsigned charcolor2)  
  135.  
  136.       
  137.     return sqrt(((float)color1[0]-(float)color2[0])*((float)color1[0]-(float)color2[0])+  
  138.         ((float)color1[1]-(float)color2[1])*((float)color1[1]-(float)color2[1])+  
  139.         ((float)color1[2]-(float)color2[2])*((float)color1[2]-(float)color2[2]));      
  140.  
  141.   
  142. float LasySnapping::minDistance(unsigned charcolor, vector points)  
  143.  
  144.     float distance -1;  
  145.     for(int =0 points.size(); i++)  
  146.      
  147.         unsigned char(unsigned char*)image->imageData points[i].y image->widthStep   
  148.             points[i].x image->nChannels;  
  149.         float colorDistance(p,color);  
  150.         if(distance  
  151.          
  152.             distance d;  
  153.          
  154.         else  
  155.          
  156.             if(distance d)  
  157.              
  158.                 distance d;  
  159.              
  160.          
  161.      
  162.   
  163.     return distance;  
  164.  
  165.   
  166. bool LasySnapping::isPtInVector(CvPoint pt, vector points)  
  167.  
  168.     for(int =0 points.size(); i++)  
  169.      
  170.         if(pt.x == points[i].x && pt.y == points[i].y)  
  171.          
  172.             return true 
  173.          
  174.      
  175.     return false 
  176.  
  177. void LasySnapping::getE1(unsigned charcolor,floatenergy)  
  178.  
  179.     // average distance  
  180.     float df colorDistance(color,avgForeColor);  
  181.     float db colorDistance(color,avgBackColor);  
  182.     // min distance from background points and forground points  
  183.     // float df minDistance(color,forePts);  
  184.     // float db minDistance(color,backPts);  
  185.     energy[0] df/(db+df);  
  186.     energy[1] db/(db+df);  
  187.  
  188.   
  189. float LasySnapping::getE2(unsigned charcolor1,unsigned charcolor2)  
  190.  
  191.     const float EPSILON 0.01;  
  192.     float lambda 100;  
  193.     return lambda/(EPSILON+  
  194.         (color1[0]-color2[0])*(color1[0]-color2[0])+  
  195.         (color1[1]-color2[1])*(color1[1]-color2[1])+  
  196.         (color1[2]-color2[2])*(color1[2]-color2[2]));  
  197.  
  198.   
  199. int LasySnapping::runMaxflow()  
  200.     
  201.     const float INFINNITE_MAX 1e10;  
  202.     int indexPt 0;  
  203.     for(int 0; image->height; ++)  
  204.      
  205.         unsigned char(unsigned char*)image->imageData *image->widthStep;  
  206.         for(int 0; image->width; ++)  
  207.          
  208.             // calculate energe E1  
  209.             float e1[2]={0};  
  210.             if(isPtInVector(cvPoint(w,h),forePts))  
  211.              
  212.                 e1[0] =0;  
  213.                 e1[1] INFINNITE_MAX;  
  214.              
  215.             else if  
  216.                 (isPtInVector(cvPoint(w,h),backPts))  
  217.              
  218.                 e1[0] INFINNITE_MAX;  
  219.                 e1[1] 0;  
  220.              
  221.             else   
  222.              
  223.                 getE1(p,e1);  
  224.              
  225.   
  226.             // add node  
  227.             graph->add_node();  
  228.             graph->add_tweights(indexPt, e1[0],e1[1]);  
  229.   
  230.             // add edge, 4-connect  
  231.             if(h && 0)  
  232.              
  233.                 float e2 getE2(p,p-3);  
  234.                 graph->add_edge(indexPt,indexPt-1,e2,e2);  
  235.                 e2 getE2(p,p-image->widthStep);  
  236.                 graph->add_edge(indexPt,indexPt-image->width,e2,e2);  
  237.              
  238.               
  239.             p+= 3;  
  240.             indexPt ++;              
  241.          
  242.      
  243.       
  244.     return graph->maxflow();  
  245.  
  246.   
  247. IplImage* LasySnapping::getImageMask()  
  248.  
  249.     IplImage* gray cvCreateImage(cvGetSize(image),8,1);   
  250.     int indexPt =0;  
  251.     for(int =0; image->height; h++)  
  252.      
  253.         unsigned char(unsigned char*)gray->imageData h*gray->widthStep;  
  254.         for(int =0 ;w width; w++)  
  255.          
  256.             if (graph->what_segment(indexPt) == GraphType::SOURCE)  
  257.              
  258.                 *p 0;  
  259.              
  260.             else  
  261.              
  262.                 *p 255;  
  263.              
  264.   
  265.             p++;  
  266.             indexPt ++;  
  267.          
  268.      
  269.     return gray;  
  270.  
  271.   
  272. // global  
  273. vector forePts;  
  274. vector backPts;  
  275. int currentMode 0;// indicate foreground or background, foreground as default  
  276. CvScalar paintColor[2] {CV_RGB(0,0,255),CV_RGB(255,0,0)};  
  277.   
  278. IplImage* image NULL;  
  279. charwinName "lazySnapping" 
  280. IplImage* imageDraw NULL;  
  281. const int SCALE 4;  
  282.   
  283. void on_mouse( int event, int x, int y, int flags, void 
  284.      
  285.     ifevent == CV_EVENT_LBUTTONUP  
  286.      
  287.         if(backPts.size() == && forePts.size() == 0)  
  288.          
  289.             return 
  290.          
  291.         LasySnapping ls;  
  292.         IplImage* imageLS cvCreateImage(cvSize(image->width/SCALE,image->height/SCALE),  
  293.             8,3);  
  294.         cvResize(image,imageLS);  
  295.         ls.setImage(imageLS);  
  296.         ls.setBackgroundPoints(backPts);  
  297.         ls.setForegroundPoints(forePts);  
  298.         ls.runMaxflow();  
  299.         IplImage* mask ls.getImageMask();  
  300.         IplImage* gray cvCreateImage(cvGetSize(image),8,1);  
  301.         cvResize(mask,gray);  
  302.         // edge  
  303.         cvCanny(gray,gray,50,150,3);  
  304.           
  305.         IplImage* showImg cvCloneImage(imageDraw);  
  306.         for(int =0; image->height; ++)  
  307.          
  308.             unsigned charpgray (unsigned char*)gray->imageData gray->widthStep*h;  
  309.             unsigned charpimage (unsigned char*)showImg->imageData showImg->widthStep*h;  
  310.             for(int width  =0; width image->width; width++)  
  311.              
  312.                 if(*pgray++ !=  
  313.                  
  314.                     pimage[0] 0;  
  315.                     pimage[1] 255;  
  316.                     pimage[2] 0;  
  317.                  
  318.                 pimage+=3;                  
  319.              
  320.          
  321.         cvSaveImage("t.bmp",showImg);  
  322.         cvShowImage(winName,showImg);  
  323.         cvReleaseImage(&imageLS);  
  324.         cvReleaseImage(&mask);  
  325.         cvReleaseImage(&showImg);  
  326.         cvReleaseImage(&gray);  
  327.      
  328.     else ifevent == CV_EVENT_LBUTTONDOWN  
  329.      
  330.   
  331.      
  332.     else ifevent == CV_EVENT_MOUSEMOVE && (flags CV_EVENT_FLAG_LBUTTON))  
  333.      
  334.         CvPoint pt cvPoint(x,y);  
  335.         if(currentMode == 0)  
  336.         {//foreground  
  337.             forePts.push_back(cvPoint(x/SCALE,y/SCALE));  
  338.          
  339.         else  
  340.         {//background  
  341.             backPts.push_back(cvPoint(x/SCALE,y/SCALE));  
  342.          
  343.         cvCircle(imageDraw,pt,2,paintColor[currentMode]);  
  344.         cvShowImage(winName,imageDraw);  
  345.      
  346.  
  347. int main(int argc, char** argv)  
  348.     
  349.     //if(argc != 2)  
  350.     //{  
  351.      //   cout<<"command lazysnapping inputImage"<<endl;  
  352.      //   return 0;  
  353.    // }  
  354.   
  355.     string image_name;  
  356.     cout<<"input image name: "<<endl;  
  357.     cin>>image_name;  
  358.   
  359.     cvNamedWindow(winName,1);  
  360.     cvSetMouseCallback( winName, on_mouse, 0);  
  361.       
  362.     image cvLoadImage(image_name.c_str(),CV_LOAD_IMAGE_COLOR);  
  363.     imageDraw cvCloneImage(image);  
  364.     cvShowImage(winName, image);  
  365.     for(;;)  
  366.      
  367.         int cvWaitKey(0);  
  368.         (char)c;  
  369.         if(c == 27)  
  370.         {//exit  
  371.             break 
  372.          
  373.         else if(c == 'r' 
  374.         {//reset  
  375.             image cvLoadImage(image_name.c_str(),CV_LOAD_IMAGE_COLOR);  
  376.             imageDraw cvCloneImage(image);  
  377.             forePts.clear();  
  378.             backPts.clear();  
  379.             currentMode 0;  
  380.             cvShowImage(winName, image);  
  381.          
  382.         else if(c == 'b' 
  383.         {//change to background selection  
  384.             currentMode 1;  
  385.         }else if(c == 'f' 
  386.         {//change to foreground selection  
  387.             currentMode 0;  
  388.          
  389.      
  390.     cvReleaseImage(&image);  
  391.     cvReleaseImage(&imageDraw);  
  392.     return 0;  
  393.  


 

 

 

 

参考文献

[1] Y. Boykov, and M. P. Jolly, “Interactive graph cuts for optimal boundary and region segmentation ofobjects in N-D images”,Proceeding ofIEEE International Conference on Computer Vision, 1:105~112, July 2001.

[2] C. Rother, A. Blake, and V. Kolmogorov, “Grabcut – interactive foreground extractionusing iterated graph cuts”,Proceedingsof ACM SIGGRAPH 2004, 23(3):307~312, August 2004.

[3] A. Agarwala, M. Dontcheva, M. Agrawala,et al, “Interactive digital photomontage”,Proceedings of ACM SIGGRAPH 2004, 23(3):294~302, August 2004.

[4] Y. Li, J. Sun, C. Tang,et al, “Interacting withimages: Lazy snapping”,Proceedingsof ACM SIGGRAPH 2004, 23(3):303~308, August 2004.

[5] A. Blake, C. Rother, M. Brown,et al, “Interactive ImageSegmentation using an adaptive GMMRF model”.Proceedings of European Conference on Computer Vision, pp. 428~441,May 2004.

[6] V. Kwatra, A. Schodl, I. Essa,et al, “Graphcut Textures:Image and Video Synthesis Using Graph Cuts”.Proceedings of ACM Siggraph 2003, pp.277~286, Augst 2003.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值