如何在课堂上使用cv::setMouseCallback

How to use cv::setMouseCallback in class?

本文关键字:cv setMouseCallback 课堂      更新时间:2023-10-16

我想在设置类中使用cv::setMouseCallback来选择图片的一个区域。这是我的代码:

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);
}

我得到了大量未定义的参考设置:coor,设置:src,设置:color。我很难理解什么是静态的才能工作。这是我的标题:

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;

我的代码中缺少什么?

由于OpenCV有一个类似C的接口,它不接受成员函数作为回调,但您可以使用标准方法来克服这一点,并将类实例作为userdata参数传递,然后将其强制转换回实例并调用成员方法。以下是一个片段:

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);
}

希望这能解释这个想法,我是在线写的,所以我很抱歉有任何拼写错误。

您还可以使用指向对象的全局指针,并从非成员回调函数调用成员函数。

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);
   ...
}

它可能对某些人有用。我的版本没有使用全局指针,但有朋友函数:

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
}
...