2

How can call OnMouse defined in a class in setMouseCallback?

Normally it is like that:

cv::setMouseCallback( String, onMouse, 0 );

Here is my program:

Camera_Height.h:

class CameraHeight
{

public:
  void onMouse( int, int, int, int, void*);
};

Camera_Height.cpp:

void CameraHeight::onMouse( int event, int x, int y, int, void* )
{
   //processing
}

main.cpp:

How can I use onMouse in setMouseCallback

CameraHeight camh1;
cv::setMouseCallback( String, onMouse, 0 );
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Ja_cpp
  • 2,426
  • 7
  • 27
  • 49
  • Do you actually need to use an class instance in this case? What is `Camera_Height`? What function does it serve? Do you need multiple instances of it, each with their own data and callback acting on that per-instance data? If not, then don't use an instance; just use a free function. (Or an entirely static class, but then what's the point of making it a class?) – underscore_d Jun 13 '16 at 15:30
  • [There you go!](http://stackoverflow.com/a/15606231/176769) – karlphillip Jun 13 '16 at 16:51
  • @karlphillip this is not in a class! – Ja_cpp Jun 13 '16 at 20:52

3 Answers3

4

setMouseCallback() does not accept a pointer-to-member-function for the callback, it expects a standalone function instead. As such, if you want to use a class method, you must declare it as static to remove its this pointer.

To access instance members of your class, the callback needs a pointer to an instance of your class. The last parameter of setMouseCallback is a user-provided pointer that is passed to the callback:

SetMouseCallback

Sets mouse handler for the specified window

C++: void setMouseCallback(const string& winname, MouseCallback onMouse, void* userdata=0 )

C: void cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse, void* param=NULL )

Python: cv.SetMouseCallback(windowName, onMouse, param=None) → None

Parameters:
- winname – Window name
- onMouse – Mouse callback. See OpenCV samples, such as https://github.com/Itseez/opencv/tree/master/samples/cpp/ffilldemo.cpp, on how to specify and use the callback.
- userdata – The optional parameter passed to the callback.

You can use that parameter to pass your camh1 object to the callback:

Camera_Height.h:

class CameraHeight
{
public:
  static void onMouse( int evt, int x, int y, int flags, void* param );
};

Camera_Height.cpp:

void CameraHeight::onMouse( int evt, int x, int y, int flags, void* param )
{
   CameraHeight *pThis = (CameraHeight*) param; 
   // use pThis as needed...
}

main.cpp:

CameraHeight camh1;
cv::setMouseCallback( String, &CameraHeight::onMouse, &camh1 );

I would suggest moving setMouseCallback inside the CameraHeight class, where its constructor sets the callback and its destructor clears the callback:

Camera_Height.h:

class CameraHeight
{
private:
   string m_winname;
   static void onMouse( int evt, int x, int y, int flags, void* param );
public:
  CameraHeight(const string &winname);
  ~CameraHeight();
};

Camera_Height.cpp:

CameraHeight::CameraHeight(const string &winname)
    : m_winname(winname)
{
    cv::setMouseCallback(m_winname, &CameraHeight::onMouse, this);
}

CameraHeight::~CameraHeight()
{
    cv::setMouseCallback(m_winname, NULL, 0);
}

void CameraHeight::onMouse( int evt, int x, int y, int flags, void* param )
{
   CameraHeight *pThis = (CameraHeight*) param; 
   // use pThis as needed...
}

main.cpp:

CameraHeight camh1( String );
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

You should make onMouse static and then call it : &CameraHeight::onMouse.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • 1
    This is likely to make things worse, not better. – Lightness Races in Orbit Jun 13 '16 at 15:19
  • 1
    ...which is only useful if the function does not require any per-instance data, or you pass the instance as a user pointer, etc. Either way, it doesn't seem to answer the question as stated. – underscore_d Jun 13 '16 at 15:19
  • @underscore_d Indeed, you would usually pass the object pointer if you need object data. – Hatted Rooster Jun 13 '16 at 15:19
  • @LightnessRacesinOrbit That depends on if OP needs instance data. – Hatted Rooster Jun 13 '16 at 15:29
  • ...and the callback here doesn't seem to provide a user-data pointer. So that seems like a no-go. – underscore_d Jun 13 '16 at 15:29
  • @RemyLebeau Oh, so I'm guessing that's what the `0` was meant to represent? That wasn't evident. If only there was some kind of self-documenting constant we could use to indicate omitted pointers... we could call it a 'null pointer' or something... [ahem] +1 to your good answer. – underscore_d Jun 13 '16 at 18:31
  • @underscore_d: Yes, the 0 in the OP's example is the data pointer. [Read the documentation](http://docs.opencv.org/2.4/modules/highgui/doc/user_interface.html#setmousecallback). In C++, a 0 can be assigned to a pointer, it is the same as assigning NULL (which is usually an alias for 0) or nullptr (in C++11 and later). – Remy Lebeau Jun 13 '16 at 20:37
  • @RemyLebeau I think that was sarcasm. – Hatted Rooster Jun 13 '16 at 20:48
  • @RemyLebeau Yeah, sarcasm fails again. My real point was that no reader would need to consult API docs vs a generic example like this if the code used idiomatic C++, which represents null pointers semantically and (via `nullptr`) in a more typesafe way. Using `0` here is an opaque and potentially dangerous piece of historical baggage. Not OP's fault, because here's the funny thing: that doc writes `NULL` for C ('better than nothing' for that lang) yet just plain old `0` for C++, even though C++ always had `NULL` even before the superior `nullptr` was introduced. I can't even. – underscore_d Jun 13 '16 at 22:23
0

@Remy Lebeau Thanks your answer is right, it helps me a lot.. But after that I get an error that a static member function can't call a member variable of the same class! But I solve it in this way:

void CameraHeight::onMouse( int event, int x, int y, int flags, void* param ) { 
    CameraHeight *anInstance = static_cast<CameraHeight *>(param); 
  }

and to access to CameraHeight instance member inside CameraHeight::onMouse (ex int aa;):

anInstance->aa;
Ja_cpp
  • 2,426
  • 7
  • 27
  • 49