I have a question about how to define the callback for trackbars in OpenCV when working with classes in C++.
When I define my trackbar let's say in the constructor method of my .cpp class how can I define the callback?
I have been trying to work with function pointers but it doesn't work out. I guess I must be doing something very wrong :-)
This is my header file:
class SliderwithImage {
public:
SliderwithImage(void);
~SliderwithImage(void);
void sliderCallBack(int pos);
};
This is the implementation file:
#include "SliderwithImage.h"
void SliderwithImage::sliderCallBack(int pos) {
}
SliderwithImage::SliderwithImage(void) {
const char* windowName = "window";
int lowvalue =1;
namedWindow(windowName, CV_GUI_EXPANDED);
createTrackbar("mytrackbar", windowName, &lowvalue, 255, sliderCallBack);
}
SliderwithImage::~SliderwithImage(void) {
}
Obviously the createTrackbar method does not recognize sliderCallBack... I guess it's a problem of scope. But I am not sure how to solve this?
Any help would be appreciated.
Thank you very much.
The callback function must be static or global, but you can pass it a reference to an object you want to operate on (see this post on the OpenCV Users mailing list).
The createTrackbar method has a userdata parameter which is passed to the calling function. In C there is an undocumented cvCreateTrackbar2 method, defined in highgui_c.h, which has the same functionality:
CVAPI(int) cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
int* value, int count, CvTrackbarCallback2 on_change,
void* userdata CV_DEFAULT(0));
These methods let you create a class with a static callback function that takes a pointer to an object of that class. You can create the trackbar like so:
cv:createTrackbar("Label", "Window" &variable, MAX_VAL, &MyClass::func, this);
The callback would look something like this:
void MyClass:func(int newValue, void * object) {
MyClass* myClass = (MyClass*) object;
// ...do stuff.
}
Note that you don't need to explicitly update the variable yourself as long as you provided a pointer to it when creating the trackbar (as above), but if you need to process it first I suggest you set it explicitly in the callback function.
You have to implement the callback function either as a global function or a static member function. To make it more OOP look, you might prefer to implement it as a static member function:)
I am using a different solution to obtain the slider value in a class variable (in my case to obtain chosen rotation angle of a live video stream). The int* value in the createTrackbar function is a public class variable which is then used within a loop (while the video is acquired, but this might messily work repeatedly redrawing a single image).
Not the best solution but it works for me.
cv::createTrackbar("Rotation Angle(deg)", "Preview", &rotationAngle,
alpha_slider_max, NULL);
for(;;)
{
int rotAngle = this -> rotationAngle;
cv::Mat frame;
cv::Mat rot_frame;
this -> capture >> frame;
rot_frame = rotateVideo (frame, rotAngle);
imshow("Preview", rot_frame);
if(cv::waitKey(30) >= 0) break;
}
Related
I am very new to the boost libraries.
I was trying to accomplish something for a graphical program, by binding the callbacks passed
to glutDisplayFunc(), etc to a single class.
I wanted to accomplish this without having some constant global class object.
To explain in code:
class CallbackHolder {
public:
void dostuff(void) {
// etc.
}
};
void bind() {
glutIdleFunc((new CallbackHolder())->dostuff);
}
I know this is possible through the usage of boost::bind and boost::function.
One issue I did see however was converting the boost::function back to a normal function pointer.
How would you accomplish this?
You can't convert from boost::function to a normal function pointer, and you can't convert from a member function pointer to a normal function pointer. There are workarounds for functions accepting callback where you can provide user data.
Unfortunately the glut interface doesn't let you provide user data. This means you're stuck with the ugliest solution, using a global variable and a normal function.
class CallbackHolder {
public:
void dostuff(void) {
// etc.
}
};
CallbackHolder * g_callbackHolder = NULL;
void call_callback_holder(void) {
if(g_callbackHolder) g_callbackHolder->dostuff();
}
void bind() {
g_callbackHolder = new CallbackHolder();
glutIdleFunc( &call_callback_holder );
}
I'm using an API that requires me to pass a function pointer as a callback. I'm trying to use this API from my class in C++ but I'm getting compilation errors.
The API definition is:
typedef void (__stdcall *STREAM_CALLBACK)(void *userdata);
__declspec(dllimport) int __stdcall set_stream_callback(
STREAM_CALLBACK streamCB, void *userdata);
One example file, provided by the third party, is:
void __stdcall streamCB(void *userdata)
{
// callback implementation
}
int main(int argc, const char argv[])
{
int mid = 0;
set_stream_callback(streamCB, &mid);
}
And that works fine.
However when I try to use that in a class, I have an error:
error C3867: 'MyClass::streamCB': function call missing argument list;
use '&MyClass::streamCB' to create a pointer to member
The suggestion to use
&MyClass::streamCB
doesn't work.
I understood that the set_stream_callback only accepts a non-member function.
The problem is very similar to
How can I pass a class member function as a callback?
in which Johannes makes a concise suggestion, however I do not understand it very well. Could anyone expand a bit, if I am correct that it is relevant to this question?
I have tried:
void __stdcall MyClass::streamCB(void *userdata)
{
// callback implementation
}
static void MyClass::Callback( void * other_arg, void * this_pointer ) {
MyClass * self = static_cast<ri::IsiDevice*>(this_pointer);
self->streamCB( other_arg );
}
//and in the constructor
int mid = 0;
set_stream_callback(&MyClass::Callback, &mid);
But
error C2664: 'set_stream_callback' : cannot convert parameter 1 from
'void (__cdecl *)(void *,void *)' to 'STREAM_CALLBACK'
How do I get around this?
Edit1: Also, I want to use userdata inside the streamCB callback.
The idea of calling a member function from a callback taking only non-member functions is to create a wrapper for you member function. The wrapper obtains an object from somewhere and then calls the member function. If the callback is reasonably well designed it will allow you to pass in some "user data" which you'd use to identify your object. You, unfortunately, left out any details about your class so I'm assuming it looks something like this:
class MyClass {
public:
void streamCB() {
// whatever
}
// other members, constructors, private data, etc.
};
With this, you can set up your callback like so:
void streamCBWrapper(void* userData) {
static_cast<MyClass*>(userData)->streamCB()
}
int main() {
MyClass object;
set_stream_callback(&streamCBWrapper, &object);
// ...
}
There are various games you can play with how to create the streamCBWrapper function (e.g., you can make it a static member of your class) but all come down to the same: you need to restore your object from the user data and call the member function on this object.
You can achieve what you want to do by turning the userdata into a property of MyClass. Then you don't have to pass it to MyClass::Callback, which would be impossible, since you can only pass one parameter, and it would be the object instance.
Here's an example.
void __stdcall MyClass::streamCB()
{
// callback implementation
}
static void MyClass::Callback(void * this_pointer ) {
MyClass * self = static_cast<MyClass>(this_pointer);
self->streamCB();
}
MyClass::MyClass(void *userdata) {
// do whatever you need to do with userdata
// (...)
// and setup the callback at C level
set_stream_callback(&MyClass::Callback, (void *)this);
}
In your example, the int mid variable would become a property of that class, and thus be accessible from the callback implementation streamCB.
I am trying to write a nodejs bindings for a C++ library and I seem to have hit a roadblock.
I am working on trying to make all the calls to the C++ library asynchronous and thats why I am using libuv. I am basically following this tutorial.
I want to be able to call class member functions from libuv's uv_queue_work. Have a look at this code --
class test {
private:
int data;
void Work(uv_work_t *req);
void After(uv_work_t *req);
public:
Handle<Value> Async(const Arguments& args) {
HandleScope scope;
Local<Function> callback = Local<Function>::Cast(args[0]);
int status = uv_queue_work(uv_default_loop(), **something**, Work, After);
assert(status == 0);
return Undefined();
}
};
Basically I expect the Work and After functions to work on the data element of the class. However this doesnt seem to work. I have tried typecasting the pointers to Work and After after from type void test::(*)(uv_work_t*) to void (*)(uv_work_t*). But that also doesnt seem to work.
Could you guys give me some tips on how to work around this??
So as you've realized, you cannot call the member functions directly.
The second argument "something" is of type uv_work_t, which has a member "void* data".
What you will need to do is create static methods inside your class for "Work" and "After", create a uv_work_t structure, and assign data to "this".
Once that is done inside your static "Work" and "After" methods you do a static cast on "req->data" (To your class type) and then call your member functions.
For example:
uv_work_t* baton = new uv_work_t();
baton->data = this;
int status = uv_queue_work(uv_default_loop(), baton, StaticWork, StaticAfter);
And then in the static methods
test* myobj = static_cast<test>(req->data);
myobj->Work();
And similar code for the StaticAfter function
Obligatory - I'm a newbie. Have a job that involves programming and I'm teaching myself as I go. Needless to say as a teacher I get things wrong frequently and thoroughly.
Where I'm at right now: I've created the class "Graph", it (surprisingly enough) makes graphs. But now I want to make it so that on a mouse click I modify the graph. But I can't seem to get a mouse handler to be a member function of the class.
cv::setMouseCallback(windowName, onMouse, 0); // Set mouse handler to be onMouse
Doesn't work with
cv::setMouseCallback(windowName, Graph::onMouse, 0);
It gives me lack of parameter errors. According to this I can't make it a member function. After following the answer given, it compiles but my this pointer is nulled. Ugh.
OnMouse looks like this:
void onMouse(int event, int x, int y,int, void*)
{
if (event == CV_EVENT_LBUTTONDOWN)
{
cvMoveWindow("Window", 500, 500); //Just to see if stuff happened
}
return;
}
I don't care about moving the window, I want to modify the graph itself - which is stored as a cv::Mat variable in a Graph object. And I can't figure out how to do it.
Any help would be appreciated, and I really hope this wasn't just gibberish.
Yes callback functions in C++ are a joy, aren't they? You actually have to give OpenCV a function (not a class method) as you've already found out. However, you can hack around this awfulness using the following technique:
class MyClass
{
public:
void realOnMouse(int event, int x, int y, int flags)
{
// Do your real processing here, "this" works fine.
}
};
// This is a function, not a class method
void wrappedOnMouse(int event, int x, int y, int flags, void* ptr)
{
MyClass* mcPtr = (MyClass*)ptr;
if(mcPtr != NULL)
mcPtr->realOnMouse(event, x, y, flags);
}
int main(int argv, char** argc)
{
// OpenCV setup stuff...
MyClass processor;
cv::setMouseCallback(windowName, wrappedOnMouse, (void*)&processor);
// Main program logic
return 0;
}
That last parameter on setMouseCallback is quite useful for overcoming some of the problems you usually encounter like this.
You can also use the onMouse method as a static method.
class Graph
{
public:
static void onMouse(int event, int x, int y, void* param)
{
//Your code here
}
//Everything else you may need
}
Now you should be able to call the onMouse method with:
cv::setMouseCallback(windowName, onMouse, (void*) param);
The param can be NULL or whatever you want to pass as parameter to the method, but you'll need to make a type-cast to the desired type.
Hope this was useful.
Bye.
First of all I have to admit that my programming skills are pretty limited and I took over a (really small) existing C++ OOP project where I try to push my own stuff in. Unfortunately I'm experiencing a problem which goes beyond my knowledge and I hope to find some help here. I'm working with a third party library (which cannot be changed) for grabbing images from a camera and will use some placeholder names here.
The third party library has a function "ThirdPartyGrab" to start a continuous live grab and takes a pointer to a function which will be called every time a new frame arrives. So in a normal C application it goes like this:
ThirdPartyGrab (HookFunction);
"HookFunction" needs to be declared as:
long _stdcall HookFunction (long, long, void*);
or "BUF_HOOK_FUNCTION_PTR" which is declared as
typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*);
Now I have a C++ application and a class "MyFrameGrabber" which should encapsulate everything I do. So I put in the hook function as a private member like this:
long _stdcall HookFunction (long, long, void*);
Also there is a public void function "StartGrab" in my class which should start the Grab. Inside I try to call:
ThirdPartyGrab (..., HookFunction, ...);
which (not surprisingly) fails. It says that the function call to MyFrameGrabber::HookFunction misses the argument list and I should try to use &MyFrameGrabber::HookFunction to create a pointer instead. However passing "&MyFrameGrabber::HookFunction" instead results in another error that this cannot be converted to BUF_HOOK_FUNCTION_PTR.
After reading through the C++ FAQ function pointers I think I understand the problem but can't make up a solution. I tried to make the hook function static but this also results in a conversion error. I also thought of putting the hook function outside of the class but I need to use class functions inside the hook function. Is there another way or do I need to change my whole concept?
EDIT 14.01.08:
I tested the singleton workaround since I cannot change the third party library and the void pointer is only for data that is used inside the hook function. Unfortunately it didn't worked out of the box like I hoped.... I don't know if the static function needs to be in a separate class so I put it in my "MyFrameGrabber" class:
static MyFrameGrabber& instance()
{
static MyFrameGrabber _instance;
return _instance;
}
long Hook(long, long, void*); // Implementation is in a separate cpp file
In my cpp file I have the call_hook function:
long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z)
{
return MyFrameGrabber::instance().Hook(x,y,z);
}
void
MyFrameGrabber::grab ()
{
ThirdPartyGrab(..., call_hook, ...);
}
But this gives me an error in static MatroxFrameGrabber _instance; that no matching standard constructor is found. That's correct because my MyFrameGrabber constructor looks like this:
MyFrameGrabber (void* x,
const std::string &y, int z,
std::string &zz);
I tried to put in an empty constructor MyFrameGrabber(); but this results in a linker error. Should I pass empty parameters to the MyFrameGrabber constructor in the singleton? Or do I need to have a separate Hook Class and if yes how could I access MyFrameGrabber functions? Thanks in advance.
SECOND EDIT 15.01.08:
I applied the changes and it compiles and links now. Unfortunately I cannot test this at runtime yet because it's a DLL and I have no Debug Caller Exe yet and there are other problems during initialization etc. I will mark the post as answer because I'm sure this is the right way to do this.
Your private member method has an implicit this pointer as first argument. If you write that out, it's obvious that the function signatures do not match.
You need to write a static member function, which can be passed as the callback-function to the library. The last argument to the HookFunction, a void*, looks to me very much like a cookie, where one can pass ones own pointer in.
So, all in all, it should be something like this:
class MyClass {
long MyCallback(long, long) {
// implement your callback code here
}
static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) {
return reinterpret_cast<MyClass*>(self)->MyCallback(a, b);
}
public:
void StartGrab() {
ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., this, ...);
}
};
This of course only works if the void* argument is doing what I said. The position of the this in the ThirdPartyGrab() call should be easy to find when having the complete function signature including the parameter names available.
The reason "&MyFrameGrabber::HookFunction" cannot be converted to a BUF_HOOK_FUNCTION_PTR is that, being a member of the class, it has implicitly as first parameter the "this" pointer, thus you cannot convert a member function to a non-member function: the two signatures look the same but are actually different.
I would declare an interface, defining the function to call, have your class implement it and pass the object itself instead of the callback (you can think of an interface as the object-oriented replacement of a function pointer):
class IHookInterface{
public:
virtual long HookFunction(long, long, void*) = 0;
};
class HookClass : public IHookInterface{
public:
virtual long Hook(long, long, void*) {
// your code here...
}
};
// new definition:
ThirdPartyGrab (..., IHookInterface, ...);
EDIT - other possible solution in case you cannot modify the library: use a singleton rather than a static function.
class HookClass{
public:
static HookClass& instance(){
static HookClass _instance;
return _instance;
}
long Hook(long, long, void*) {
// your code here...
}
};
long call_hook(long x,long y,void * z){
return HookClass::instance().Hook(x,y,z);
}
SECOND EDIT: you might slightly modify the singleton class with an initialization method to call the constructor with the proper parameters, but maybe it is not more elegant than the following solution, which is simpler:
class HookClass{
public:
HookClass(string x,string y...){
}
long Hook(long, long, void*) {
// your code here...
}
};
static HookClass * hook_instance = 0;
long call_hook(long x,long y,void * z){
if (0 != hook_instance){
return hook_instance->Hook(x,y,z);
}
}
int main(){
hook_instance = new HookClass("x","y");
ThirdPartyGrab(..., call_hook, ...);
}