Nicolai
Nicolai

Reputation: 343

Drawing with MouseCallback in OpenCV

Using OpenCV 2.4.3, I am trying to draw a circle on top of an image centered on the mouse (x,y) position when the user is moving the mouse, and just that circle should be there once the mouse stops moving (only the original image with just one circle drawn should be shown in that moment). I thought it was going to be easy, however, I´ve been researching and trying for a couple of hours and can´t make it work the way I described.

Im attaching my code underneath. If anyone could help out I´d be really grateful.

void my_mouse_callback( int event, int x, int y, int flags, void* param );
bool moving_mouse = false;

int main()
{
const char* name = "Circle Example";

IplImage* image_circle = cvLoadImage( "../data/lena.png" );
IplImage* image = cvLoadImage( "../data/lena.png" );

namedWindow(name, CV_WINDOW_AUTOSIZE );

// Set up the callback
cvSetMouseCallback( name, my_mouse_callback, (void*) image_circle);

//Main Loop
while(cvWaitKey(15) != 27){ 

    //If mouse is moving draw circle on top of image
    if(moving_mouse){
        cvShowImage(name, image_circle);
        moving_mouse = false;
    }
    //If mouse stops moving draw original image and reset image_cicle
    else{
        cvShowImage(name, image);
        image_circle = cvCloneImage(image);
    }
}

cvReleaseImage(&image_circle);
cvReleaseImage(&image);
cvDestroyWindow(name);
return 0;
}


// Mouse callback
void my_mouse_callback( int event, int x, int y, int flags, void* param ){

switch( event ){
    case CV_EVENT_MOUSEMOVE: 
        //Drawing a Circle
        cvCircle(param,cvPoint(x,y),25,CV_RGB(0,255,0),1);
        moving_mouse = true;
        break;

          }
    }

Upvotes: 2

Views: 3060

Answers (1)

ChronoTrigger
ChronoTrigger

Reputation: 8617

I show you one approach to do this. I explain it later and tell you a difficulty you will have:

static int mouse_x = -1;
static int mouse_y = -1;

void my_mouse_callback( int event, int x, int y, int flags, void* param )
{
  if(event == CV_EVENT_MOUSEMOVE)
  {
    mouse_x = x;
    mouse_y = y;
  }
}

int main()
{
  IplImage* image;
  IplImage* image_circle = NULL;

  ... // load image, create window, initiate callback, etc

  int x = -1;
  int y = -1;
  while(cvWaitKey(15) != 27)
  { 
    if(x != mouse_x || y != mouse_y)
    {
      x = mouse_x;
      y = mouse_y;

      cvReleaseImage(&image_circle);
      image_circle = cvCloneImage(image);
      cvCircle(image_circle,cvPoint(x,y),25,CV_RGB(0,255,0),1);
      cvShowImage(name, image_circle);
    }
  }

  ... // destroy image
}

Explanation

Here, in the mouse event, you just store the coordinates of the mouse pointer. When an event takes place, the main program will check if the mouse moved to redraw the full image again. Since you want to erase the previous circle, you must copy the original image first to draw the new circle later. You could make this smarter by just copying the part of the original image that were the previous circle was, instead of the entire image.

Problem

A problem when doing something like this in OpenCV is that you can't detect when the mouse goes out of your window, so that you will always have a circle drawn in your image. I don't think you can solve this just with OpenCV, since I don't think there is a kind of MOUSE_OUT event. You would need to look for some Qt callback or system function.

Upvotes: 2

Related Questions