How to use cv :: setMouseCallback in a class?

I want to use cv :: setMouseCallback inside my settings class to select an image area. This is my code:

void Settings::on_buttonXML_clicked(){ cv::VideoCapture webcam; webcam.open(INDEX); webcam.read(src); color = Scalar(0,0,255); coor_num = 0; xmlPath="C:/myregion.xml"; cv::namedWindow("imageWindow", CV_WINDOW_AUTOSIZE ); cv::imshow("imageWindow", src); cv::setMouseCallback( "imageWindow", onMouse, 0 ); cv::waitKey(0); } void Settings::onMouse(int event, int x, int y, int, void* ) { if (event == CV_EVENT_LBUTTONUP) { Point2f p(x, y); coor.push_back(p); line(src,p,p,color); if(coor.size()>1) line(src, p, coor[coor.size()-2], color); imshow("imageWindow", src); } else if (event == CV_EVENT_RBUTTONUP && coor.size()>2){ line(src, coor[0], coor[coor.size()-1], color); getPointsInContour(coor); imshow("imageWindow", src); waitKey(2000); exit(0); } } void Settings::savePointsAsXML(vector<Point2f> & contour){ TiXmlDocument doc; TiXmlDeclaration decl("1.0", "", ""); doc.InsertEndChild(decl); for(int i = 0; i < contour.size(); i++) { TiXmlElement point("point"); point.SetAttribute("x",contour[i].x); point.SetAttribute("y",contour[i].y); doc.InsertEndChild(point); } if(doc.SaveFile(xmlPath.c_str())) cout << "file saved succesfully.\n"; else cout << "file not saved, something went wrong!\n"; } void Settings::getPointsInContour(vector<Point2f> & contour){ vector<Point2f> insideContour; for(int j = 0; j < src.rows; j++){ for(int i = 0; i < src.cols; i++){ Point2f p(i,j); if(cv::pointPolygonTest(contour,p,false) >= 0) // yes inside insideContour.push_back(p); } } cout << "# points inside contour: " << insideContour.size() << endl; savePointsAsXML(insideContour); } 

I get tons of undefined links to Settings: coor, Settings: src, Settings: color. I am having trouble understanding what should be static to work. This is my headline:

 class Settings { private: static void onMouse(int event, int x, int y, int, void* ); static void savePointsAsXML(std::vector<cv::Point2f> & contour); static void getPointsInContour(std::vector<cv::Point2f> & contour); static cv::Scalar color; static std::vector<cv::Point2f> coor; static int coor_num; static std::string xmlPath; static cv::Mat src; 

What am I missing in my code?

+5
source share
3 answers

Since OpenCV has a C-like interface, it does not accept a member function as a callback, but you can use standard tools to overcome this and pass an instance of the class as a userdata parameter, and then return it to the instance and call the member method. Here is a snippet:

 void Settings::on_buttonXML_clicked(){ cv::VideoCapture webcam; webcam.open(INDEX); webcam.read(src); color = Scalar(0,0,255); coor_num = 0; xmlPath="C:/myregion.xml"; cv::namedWindow("imageWindow", CV_WINDOW_AUTOSIZE ); cv::imshow("imageWindow", src); cv::setMouseCallback( "imageWindow", onMouse, this ); // Pass the class instance pointer here cv::waitKey(0); } // In you header make a static and a member version of onMouse void onMouse(int event, int x, int y); static void onMouse(int event, int x, int y, int, void* userdata); // Implement it to call the member function void Settings::onMouse(int event, int x, int y, int, void* userdata) { // Check for null pointer in userdata and handle the error ... Settings* settings = reinterpret_cast<Settings*>(userdata); settings->onMouse(event, x, y); } 

Hope this explains the idea, I wrote it in a line, and so I apologize for any typos.

+10
source

You can also use a global pointer that points to your object and call a member function from a non-member callback function.

 Class SomeClass { ... public: void callback(int event, int x, int y); ... }; SomeClass* g_ptr; void onMouse(int event, int x, int y, void*) { g_ptr->callback(event, x, y); } void func(void) { SomeClass obj; g_ptr = &obj; // Make the global variable point to your object cv::namedWindow("winname"); cv::setMouseCallback("winname", onMouse, 0); ... } 
+1
source

This may be helpful for someone. My version without using global pointers, but with friends features:

 class App { public: App(); ~App(); void setWin(const std::string& _winname); ... private: void on_mouse_internal(int ev, int x, int y); std::string winname; friend void on_mouse(int ev, int x, int y, int, void* obj); ... }; void on_mouse(int ev, int x, int y, int, void* obj) { App* app = static_cast<App*>(obj); if (app) app->on_mouse_internal(ev, x, y); } App::App() { ... } App::~App() { ... } void App::setWin(const std::string& _winname) { cv::namedWindow(_winname); this->winname = _winname; cv::setMouseCallback(winname, on_mouse, this); } void App::on_mouse_internal(int ev, int x, int y) { std::cout << "X:" << x << ";Y:" << y << std::endl; // here you can specify class members } ... 
0
source

Source: https://habr.com/ru/post/1202165/


All Articles