opencv how can I select a region of image irregularly with mouse event? c/c++ [closed]

I had a little attempt at this – it is probably not the cleanest code, but should give you some ideas.

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

// Globals
bool finished=false;
Mat img,ROI;
vector<Point> vertices;

void
CallBackFunc(int event,int x,int y,int flags,void* userdata)
{
   if(event==EVENT_RBUTTONDOWN){
      cout << "Right mouse button clicked at (" << x << ", " << y << ")" << endl;
      if(vertices.size()<2){
         cout << "You need a minimum of three points!" << endl;
         return;
      }
      // Close polygon
      line(img,vertices[vertices.size()-1],vertices[0],Scalar(0,0,0));

      // Mask is black with white where our ROI is
      Mat mask= Mat::zeros(img.rows,img.cols,CV_8UC1);
      vector<vector<Point>> pts{vertices};
      fillPoly(mask,pts,Scalar(255,255,255));
      img.copyTo(ROI,mask);
      finished=true;

      return;
   }
   if(event==EVENT_LBUTTONDOWN){
      cout << "Left mouse button clicked at (" << x << ", " << y << ")" << endl;
      if(vertices.size()==0){
         // First click - just draw point
         img.at<Vec3b>(x,y)=Vec3b(255,0,0);
      } else {
         // Second, or later click, draw line to previous vertex
         line(img,Point(x,y),vertices[vertices.size()-1],Scalar(0,0,0));
      }
      vertices.push_back(Point(x,y));
      return;
   }
}

int main()
{
   // Read image from file 
   img=imread("demo.jpg");

   // Check it loaded
   if(img.empty()) 
   { 
      cout << "Error loading the image" << endl;
      exit(1);
   }

   //Create a window
   namedWindow("ImageDisplay",1);

   // Register a mouse callback
   setMouseCallback("ImageDisplay",CallBackFunc,nullptr);

   // Main loop
   while(!finished){
      imshow("ImageDisplay",img);
      waitKey(50);
   }

   // Show results
   namedWindow("Result",1);
   imshow("Result",ROI);
   waitKey(5000);
}

enter image description here


Explanation of the Callback

At the beginning of main() I do this:

setMouseCallback("ImageDisplay",CallBackFunc,nullptr);

and that tells OpenCV to call the function CallBackFunc() for us whenever the mouse moves or is clicked.

CallBackFunc() is just a normal function like any other function. However, we don’t ever call it ourselves – OpenCV calls it for us asynchronously (when we aren’t expecting it). Because of that, we can’t see any returned value from the function – since we never called it – and that is why it is declared as:

void CallBackFunc(...)

because it returns nothing, or a void, or a dirty great void of nothingness.

Ok, let’s move on to the parameters it is called with. Basically, when the designers of OpenCV wrote the setMouseCallback() function, they couldn’t know what I would want to pass to it as a parameter – maybe I would want to pass a filename, maybe I would want to pass a text string to draw on the image when the mouse is clicked, maybe I would want to pass a variable that I wanted updated with the mouse position. It could be anything. So, as they didn’t know, they decided to say it is a “pointer to anything” and I can use it for whatever I like. Well, nothing is anything, so a pointer to void can point to anything. So, they say just pass a pointer to void that you know the meaning of. Then, inside CallBackFunc() you can just cast the pointer to whatever it was you passed since you know what it is.

So, in summary a pointer to void is just a place-marker for a pointer to something and you can decide what that something is without the OpenCV designers needing to know.

Hope that helps!

Leave a Comment