【问题标题】:opencv how can I select a region of image irregularly with mouse event? c/c++ [closed]opencv如何使用鼠标事件不规则地选择图像区域? c/c++ [关闭]
【发布时间】:2017-06-30 15:35:12
【问题描述】:

我最近在学习opencv。有没有办法使用鼠标事件选择图像区域?我已经尝试了三角形之一。如果我想选择特定区域而不是三角形怎么办?谢谢!

【问题讨论】:

  • 1) 没有 C/C++ 语言。只有不同的语言 C 和 C++。 2) OpenCV 现在使用 C++ 接口 3) 不要垃圾标签。 4)阅读How to Ask,听从建议。 4) 您的具体问题是什么?有问题的代码在哪里? 5) 我们不是辅导网站。
  • 可能不会。 Open CV 是一个计算机视觉库,它有一些用于显示图像的原始 GUI 函数,使开发更容易,但是如果你想要一个复杂的 GUI 操作,比如让鼠标描述一个不规则的区域,你需要在窗口中编写代码系统。
  • 注册回调以接收鼠标点击。将单击的点保存在点向量中。双击时用这些点绘制一个多边形。从多边形制作 ROI。

标签: c++ opencv


【解决方案1】:

我对此进行了一些尝试——它可能不是最干净的代码,但应该会给你一些想法。

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


回调说明

main()的开头我这样做:

setMouseCallback("ImageDisplay",CallBackFunc,nullptr);

这告诉 OpenCV 在鼠标移动或点击时为我们调用函数CallBackFunc()

CallBackFunc() 和其他函数一样只是一个普通函数。然而,我们从来没有自己调用它 - OpenCV 为我们异步调用它(当我们不期望它时)。因此,我们看不到函数的任何返回值——因为我们从未调用过它——这就是为什么它被声明为:

void CallBackFunc(...)

因为它什么也没有返回,或者是一个虚无,或者一个肮脏的虚无。

好的,让我们继续讨论调用它的参数。基本上,当 OpenCV 的设计者编写 setMouseCallback() 函数时,他们不知道我想将什么作为参数传递给它——也许我想传递一个文件名,也许我想想要在单击鼠标时传递一个文本字符串以在图像上绘制,也许我想传递一个我想用鼠标位置更新的变量。它可以是任何东西。所以,正如他们不知道的那样,他们决定说它是一个“指向任何东西的指针”,我可以将它用于我喜欢的任何事情。好吧,什么都不是,所以指向 void 的指针可以指向任何东西。因此,他们说只需将指针传递给您知道其含义的 void。然后,在 CallBackFunc() 中,您可以将指针转换为您传递的任何内容,因为您知道它是什么。

因此,总而言之,指向 void 的指针只是指向某物的指针的位置标记,您可以在 OpenCV 设计者需要知道的情况下决定该物是什么。

希望有帮助!

【讨论】:

  • 哇!谢谢马克!这正是我正在寻找的。我会好好看看它再次感谢人!
  • 感谢您的精彩回答!但是你能用 C++ 术语解释一下鼠标回调到底是什么吗?我仍然对调用函数时必须使用的静态强制转换和 void* 感到非常困惑。
  • 我在底部添加了一点解释 - 希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多