#include <iostream>
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 GC_FGD pixels\n"
        "\n"
        "\tCTRL+right mouse button - set GC_PR_BGD pixels\n"
        "\tSHIFT+right mouse button - set GC_PR_FGD pixels\n" << endl;
}
static void getBinMask( 
const Mat& comMask, 
Mat& binMask )
 {
    binMask = comMask & 1;
}
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 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;
    uchar rectState, lblsState, prLblsState;
     bool isInitialized;
    vector<Point> 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;
    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;
    reset();
}
{
    if( image->empty() || winName->empty() )
        return;
    if( !isInitialized )
    else
    {
        getBinMask( mask, binMask );
        image->copyTo( res, binMask );
    }
    vector<Point>::const_iterator it;
    for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it )
        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);
 }
void GCApplication::setRectInMask()
{
    rect.width = 
min(rect.width, image->cols-rect.x);
    rect.height = 
min(rect.height, image->rows-rect.y);
}
void GCApplication::setLblsInMask( 
int flags, 
Point p, 
bool isPr )
 {
    vector<Point> *bpxls, *fpxls;
    if( !isPr )
    {
        bpxls = &bgdPxls;
        fpxls = &fgdPxls;
    }
    else
    {
        bpxls = &prBgdPxls;
        fpxls = &prFgdPxls;
    }
    if( flags & BGD_KEY )
    {
        bpxls->push_back(p);
        circle( mask, p, radius, bvalue, thickness );
     }
    if( flags & FGD_KEY )
    {
        fpxls->push_back(p);
        circle( mask, p, radius, fvalue, thickness );
     }
}
void GCApplication::mouseClick( int event, int x, int y, int flags, void* )
{
    
    switch( event )
    {
        {
            bool isb = (flags & BGD_KEY) != 0,
                 isf = (flags & FGD_KEY) != 0;
            if( rectState == NOT_SET && !isb && !isf )
            {
                rectState = IN_PROCESS;
                rect = 
Rect( x, y, 1, 1 );
            }
            if ( (isb || isf) && rectState == SET )
                lblsState = IN_PROCESS;
        }
        break;
        {
            bool isb = (flags & BGD_KEY) != 0,
                 isf = (flags & FGD_KEY) != 0;
            if ( (isb || isf) && rectState == SET )
                prLblsState = IN_PROCESS;
        }
        break;
        if( rectState == IN_PROCESS )
        {
            rectState = SET;
            setRectInMask();
            CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
         }
        if( lblsState == IN_PROCESS )
        {
            setLblsInMask(flags, 
Point(x,y), 
false);
            lblsState = SET;
        }
        break;
        if( prLblsState == IN_PROCESS )
        {
            setLblsInMask(flags, 
Point(x,y), 
true);
            prLblsState = SET;
        }
        break;
        if( rectState == IN_PROCESS )
        {
            CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
         }
        else if( lblsState == IN_PROCESS )
        {
            setLblsInMask(flags, 
Point(x,y), 
false);
        }
        else if( prLblsState == IN_PROCESS )
        {
            setLblsInMask(flags, 
Point(x,y), 
true);
        }
        break;
    }
}
int GCApplication::nextIter()
{
    if( isInitialized )
        grabCut( *image, mask, rect, bgdModel, fgdModel, 1 );
     else
    {
        if( rectState != SET )
            return iterCount;
        if( lblsState == SET || prLblsState == SET )
        else
        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 )
{
    help();
    string filename = parser.
get<
string>(
"@input");
     if( filename.empty() )
    {
        cout << "\nDurn, empty filename" << endl;
        return 1;
    }
    {
        cout << "\n Durn, couldn't read image filename " << filename << endl;
        return 1;
    }
    const string winName = "image";
    gcapp.setImageAndWinName( image, winName );
    gcapp.showImage();
    for(;;)
    {
        switch( 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:
    return 0;
}