android opencv交互式抠图

以前我写过用opencv实现抠图,但只是简单的画一个矩形,哪些是前景哪些是背景都由opencv自己判断,最近忙完了就研究了一下交互式抠图

主要参考opencv的官方例子,不过官方例子是pc端的,所以就对例子进行了修改

官方例子代码

先看看效果,原图

然后是用原来的方法扣的

狗脸都没了,接下来看用交互式抠图的效果

忘了说密集恐惧症慎看了,扣完的效果

嗯,有狗脸了,接下来贴代码,先看布局

 

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.grabcut.MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="确定"
                    android:onClick="onGrabCut"/>
                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="重置"
                    android:onClick="onReset"/>
                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="前景"
                    android:onClick="onFlags"/>
                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="背景"
                    android:onClick="onFlags"/>
                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="范围"
                    android:onClick="onFlags"/>
            </LinearLayout>
        </HorizontalScrollView>

        <ImageView
            android:id="@+id/image_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:maxHeight="1000dp"
            android:background="#435434"/>
    </LinearLayout>

</android.support.constraint.ConstraintLayout>

 

ImageView的adjustViewBounds和maxHeight的功能是让ImageView根据图片大小自适应,好方便做手势操作,虽然还是有误差

java代码

 

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }
    private long gcapp;

    private int flags = 0; // 0范围,1前景,2背景

    private Bitmap bitmap;
    private ImageView imageView;

    private Bitmap bm;

    private float s = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method

        imageView = findViewById(R.id.image_view);


        bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.timg);

        bm = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);

        Mat img = new Mat();
        Utils.bitmapToMat(bitmap, img);
        Imgproc.cvtColor(img, img, Imgproc.COLOR_RGBA2RGB);
        gcapp = initGrabCut(img.nativeObj);

        imageView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(s == 0){
                    s = imageView.getWidth()*1.0f / bitmap.getWidth();
                }
                int x = (int) (event.getX()/s);
                int y = (int) (event.getY()/s);
                int type = event.getAction();
                switch (type){
                    case MotionEvent.ACTION_DOWN:
                        moveGrabCut(0,x,y,flags,gcapp);
                        break;
                    case MotionEvent.ACTION_UP:
                        moveGrabCut(1,x,y,flags,gcapp);
                        break;
                    case MotionEvent.ACTION_CANCEL:
                        moveGrabCut(1,x,y,flags,gcapp);
                        break;
                    case MotionEvent.ACTION_MOVE:
                        moveGrabCut(2,x,y,flags,gcapp);
                        break;
                }


                return true;
            }
        });


    }

    public void onFlags(View view){
        Button button = (Button) view;
        if("范围".equals(button.getText().toString())){
            flags = 0;
        }else if("前景".equals(button.getText().toString())){
            flags = 1;
        }else if("背景".equals(button.getText().toString())){
            flags = 2;
        }
    }
    public void onReset(View view){
        flags = 0;
        reset(gcapp);
    }
    public void onGrabCut(View view){
        Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();
                Log.d("grabCut","开始处理");
                if(grabCut(gcapp)){
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            grabCutOver(gcapp);
                        }
                    });
                }
                Log.d("grabCut","结束处理");

            }
        };
        thread.start();
    }

    public void showImage(long image){
        Mat img = new Mat(image);
        Utils.matToBitmap(img,bm);
        imageView.setImageBitmap(bm);
    }

    public native long initGrabCut(long image);
    public native void moveGrabCut(int event, int x, int y, int flags,long gcapp);
    public native void reset(long gcapp);
    public native boolean grabCut(long gcapp);
    public native void grabCutOver(long gcapp);
}

 

c++代码

 

#include <jni.h>
#include <string>
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"


#include <iostream>

using namespace std;
using namespace cv;

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);


static void getBinMask( const Mat& comMask, Mat& binMask )
{
    if( comMask.empty() || comMask.type()!=CV_8UC1 )
        CV_Error( Error::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;
}

class GCApplication
{
public:
    enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 };
    static const int radius = 20;
    static const int thickness = -1;

    GCApplication();
    ~GCApplication();
    void reset();
    void setImageAndShowId(Mat *_image, jmethodID _showId );
    void showImage(JNIEnv *env, jobject instance) const;
    void mouseClick( int event, int x, int y, int flags, JNIEnv *env, jobject instance);
    int nextIter();
    int getIterCount() const { return iterCount; }
private:
    void setRectInMask();
    void setLblsInMask( int flags, Point p ,bool isPr);

    const Mat* image;
    jmethodID showId;


    Mat mask;
    Mat bgdModel, fgdModel;

    uchar rectState, lblsState, prLblsState;
    bool isInitialized;

    Rect rect;
    vector<Point> fgdPxls, bgdPxls, prFgdPxls, prBgdPxls;
    int iterCount;
};
GCApplication::GCApplication(){

}
GCApplication::~GCApplication(){

}
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::setImageAndShowId(Mat *_image, jmethodID _showId )
{
    if( _image->empty())
        return;
    image = _image;
    showId = _showId;
    mask.create( image->size(), CV_8UC1);
    reset();
}

void GCApplication::showImage(JNIEnv *env, jobject instance) const
{
    if( image->empty() )
        return;

    Mat res;
    Mat binMask;
    if( !isInitialized )
        image->copyTo( res );
    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);
    long img = (long) &res;
    env->CallVoidMethod(instance,showId,img);
}

void GCApplication::setRectInMask()
{
    CV_Assert( !mask.empty() );
    mask.setTo( GC_BGD );
    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) );
}

void GCApplication::setLblsInMask( int flags, Point p, bool isPr )
{
    vector<Point> *bpxls, *fpxls;
    uchar bvalue, fvalue;
    if( !isPr )
    {
        bpxls = &bgdPxls;
        fpxls = &fgdPxls;
        bvalue = GC_BGD;
        fvalue = GC_FGD;
    }
    else
    {
        bpxls = &prBgdPxls;
        fpxls = &prFgdPxls;
        bvalue = GC_PR_BGD;
        fvalue = GC_PR_FGD;
    }
    if( flags == 2 )
    {
        bpxls->push_back(p);
        circle( mask, p, radius, bvalue, thickness );
    }
    if( flags  == 1)
    {
        fpxls->push_back(p);
        circle( mask, p, radius, fvalue, thickness );
    }
}
// event:DOWN = 0,UP = 1,MOVE = 2
void GCApplication::mouseClick( int event, int x, int y, int flags ,JNIEnv *env, jobject instance)
{
    // TODO add bad args check
    switch(event){
        case 0: {
            if (flags == 0 && rectState == NOT_SET) {
                rectState = IN_PROCESS;
                rect = Rect(x, y, 1, 1);
            }
            if ( flags == 1 && rectState == SET )
                lblsState = IN_PROCESS;
            if ( flags == 2 && rectState == SET )
                prLblsState = IN_PROCESS;
        }
            break;
        case 1:{
            if(flags == 0 || flags == 1){
                if( rectState == IN_PROCESS )
                {
                    rect = Rect( Point(rect.x, rect.y), Point(x,y) );
                    rectState = SET;
                    setRectInMask();
                    CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
                    showImage(env,instance);
                }
                if( lblsState == IN_PROCESS )
                {
                    setLblsInMask(flags, Point(x,y),false);
                    lblsState = SET;
                    showImage(env,instance);
                }
            }
            if(flags == 2 && prLblsState == IN_PROCESS ){
                setLblsInMask(flags, Point(x,y),false);
                prLblsState = SET;
                showImage(env,instance);
            }
        }
            break;
        case 2:{
            if( rectState == IN_PROCESS )
            {
                rect = Rect( Point(rect.x, rect.y), Point(x,y) );
                CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
                showImage(env,instance);
            }
            else if( lblsState == IN_PROCESS )
            {
                setLblsInMask(flags, Point(x,y),false);
                showImage(env,instance);
            }
            else if( prLblsState == IN_PROCESS )
            {
                setLblsInMask(flags, Point(x,y),false);
                showImage(env,instance);
            }
        }
            break;
    }

}

int GCApplication::nextIter()
{
    if( isInitialized )
        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;
}

;

static void on_mouse(GCApplication *gcapp, int event, int x, int y, int flags,JNIEnv *env, jobject instance)
{
    gcapp->mouseClick( event, x, y, flags ,env,instance);
}

extern "C"
JNIEXPORT GCApplication * JNICALL
Java_com_example_grabcut_MainActivity_initGrabCut(JNIEnv *env, jobject instance, jlong image) {

    // TODO
    Mat *img = (Mat *) image ;
    GCApplication *gcapp = new GCApplication();

    jclass jc = env->GetObjectClass(instance);
    jmethodID showId = env->GetMethodID(jc, "showImage", "(J)V");

    gcapp->setImageAndShowId(img, showId);
    gcapp->showImage(env,instance);
    return gcapp;
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_grabcut_MainActivity_moveGrabCut(JNIEnv *env, jobject instance, jint event, jint x,
                                                  jint y, jint flags, jlong gcapp) {

    // TODO
    GCApplication *g = (GCApplication *) gcapp;
    on_mouse(g,event,x,y,flags,env,instance);
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_grabcut_MainActivity_reset(JNIEnv *env, jobject instance, jlong gcapp) {

    // TODO
    GCApplication *g = (GCApplication *) gcapp;
    g->reset();
    g->showImage(env,instance);
}extern "C"
JNIEXPORT jboolean JNICALL
Java_com_example_grabcut_MainActivity_grabCut(JNIEnv *env, jobject instance, jlong gcapp) {

    // TODO
    GCApplication *g = (GCApplication *) gcapp;
    int iterCount = g->getIterCount();
    int newIterCount = g->nextIter();
    return (jboolean) (newIterCount > iterCount);
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_grabcut_MainActivity_grabCutOver(JNIEnv *env, jobject instance, jlong gcapp) {

    // TODO
    GCApplication *g = (GCApplication *) gcapp;
    g->showImage(env,instance);
}

 

可以看出来,基本代码和官方的一样就是改了操作代码

操作顺序要说一下,要先圈范围,之后可以选前景或背景了,点完后按确定,重置完后也是先选范围,当然这个顺序是我随便写写的,不是一定要这样的顺序,可以自己修改代码,范围抠图和交互抠图也可以独立使用,并没有先后使用的顺序

百度云

密码:p44s

2020/4/16更新

想把demo上传到github,可是发现原来的demo不停报错,也不知道为啥,以前测试都没问题啊,就又改改,问题根源在java和c++的内存管理,他们是相互独立的,比如一个Mat同时存在java和c++的时候,当java把资源释放了,而c++不知道java把那个Mat释放了,c++调用的时候就崩溃了,当然反过来的情况也是一样的,所以就把资源统一由java或c++管理,最好不要混合使用

修改上传到GitHub了,RectActivity是简单的抠图,GCActivity是交互抠图,MainActivity和GrabCut这两个文件是我测试用的请无视
GrabCut

上边的官方链接失效了,我重新找了一下,防止下次又失效先复制下来

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(char** argv)
{
    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"
        <<  argv[0] << " <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;
}
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 = EVENT_FLAG_CTRLKEY;
const int FGD_KEY = EVENT_FLAG_SHIFTKEY;
static void getBinMask( const Mat& comMask, Mat& binMask )
{
    if( comMask.empty() || comMask.type()!=CV_8UC1 )
        CV_Error( Error::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;
}
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<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;
    mask.create( image->size(), CV_8UC1);
    reset();
}
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 );
    }
    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);
    imshow( *winName, res );
}
void GCApplication::setRectInMask()
{
    CV_Assert( !mask.empty() );
    mask.setTo( GC_BGD );
    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) );
}
void GCApplication::setLblsInMask( int flags, Point p, bool isPr )
{
    vector<Point> *bpxls, *fpxls;
    uchar bvalue, fvalue;
    if( !isPr )
    {
        bpxls = &bgdPxls;
        fpxls = &fgdPxls;
        bvalue = GC_BGD;
        fvalue = GC_FGD;
    }
    else
    {
        bpxls = &prBgdPxls;
        fpxls = &prFgdPxls;
        bvalue = GC_PR_BGD;
        fvalue = GC_PR_FGD;
    }
    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* )
{
    // TODO add bad args check
    switch( event )
    {
    case 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 )
            {
                rectState = IN_PROCESS;
                rect = Rect( x, y, 1, 1 );
            }
            if ( (isb || isf) && rectState == SET )
                lblsState = IN_PROCESS;
        }
        break;
    case 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 )
                prLblsState = IN_PROCESS;
        }
        break;
    case EVENT_LBUTTONUP:
        if( rectState == IN_PROCESS )
        {
            rect = Rect( Point(rect.x, rect.y), Point(x,y) );
            rectState = SET;
            setRectInMask();
            CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
            showImage();
        }
        if( lblsState == IN_PROCESS )
        {
            setLblsInMask(flags, Point(x,y), false);
            lblsState = SET;
            showImage();
        }
        break;
    case EVENT_RBUTTONUP:
        if( prLblsState == IN_PROCESS )
        {
            setLblsInMask(flags, Point(x,y), true);
            prLblsState = SET;
            showImage();
        }
        break;
    case EVENT_MOUSEMOVE:
        if( rectState == IN_PROCESS )
        {
            rect = Rect( Point(rect.x, rect.y), Point(x,y) );
            CV_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;
    }
}
int GCApplication::nextIter()
{
    if( isInitialized )
        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 )
{
    cv::CommandLineParser parser(argc, argv, "{@input| messi5.jpg |}");
    help(argv);
    string filename = parser.get<string>("@input");
    if( filename.empty() )
    {
        cout << "\nDurn, empty filename" << endl;
        return 1;
    }
    Mat image = imread(samples::findFile(filename), IMREAD_COLOR);
    if( image.empty() )
    {
        cout << "\n Durn, couldn't read image filename " << filename << endl;
        return 1;
    }
    const string winName = "image";
    namedWindow( winName, WINDOW_AUTOSIZE );
    setMouseCallback( winName, on_mouse, 0 );
    gcapp.setImageAndWinName( image, winName );
    gcapp.showImage();
    for(;;)
    {
        char c = (char)waitKey(0);
        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:
    destroyWindow( winName );
    return 0;
}

 

 

 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值