【问题标题】:OpenCV: Storing the coordinates of the points clicked by mouse left buttonOpenCV:存储鼠标左键单击的点的坐标
【发布时间】:2014-07-06 20:14:05
【问题描述】:

以下程序将给出鼠标左键单击的位置。

 void onMouse(int evt, int x, int y, int flags, void* param) {
    if(evt == CV_EVENT_LBUTTONDOWN) {
        cv::Point* ptPtr = (cv::Point*)param;
        ptPtr->x = x;
        ptPtr->y = y;
    }
}

int main() {
    cv::Point2i pt(-1,-1);//assume initial point
    cv::namedWindow("Output Window");

    Mat frame = cv::imread("chhhha.png");

    cv::setMouseCallback("Output Window", onMouse, (void*)&pt);
   int X, Y; 

    while(1)
    {
    cv::imshow("Output Window", frame);

    X=pt.x; 

    Y=pt.y; 

    cout<<"X and Y coordinates are given below"<<endl;
   cout<<X<<'\t'<<Y<<endl; 


 waitKey(10);

    }


    getch(); 
}

我想画一条连接用户点击的两点的线。我知道该函数可以画线:

C++: void line(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)

但问题是我必须为这个函数提供两个点,但是我之前的点丢失了,如下代码所示:

   void onMouse(int evt, int x, int y, int flags, void* param) {
        if(evt == CV_EVENT_LBUTTONDOWN) {
            cv::Point* ptPtr = (cv::Point*)param;
            ptPtr->x = x;
            ptPtr->y = y;
        }
    }

    int main() {
        cv::Point2i pt(-1,-1);
        cv::namedWindow("Output Window");

        Mat frame = cv::imread("chhhha.png");

        cv::setMouseCallback("Output Window", onMouse, (void*)&pt);
       int X, Y; 

        while(1)
        {
        cv::imshow("Output Window", frame);

        X=pt.x; 

        Y=pt.y; 

        cout<<"X and Y coordinates are given below"<<endl;
       cout<<X<<'\t'<<Y<<endl; 



 line(frame,  pt1,  pt2, 'r',  1,  8,  0); //here I am having only one point. This is the issue  


     waitKey(10);

        }


        getch(); 
    }

编辑

那么无论如何都要存储用户点击的点的坐标。因此,假设用户单击图像上的两个点,我们会将两次单击的 x 坐标存储在 X[0] 和 X[1] 中,类似地,Y[0] 和 Y[1] 存储 y 坐标。

然后我可以轻松地使用画线功能。请帮助我朝着这个方向前进。

提前感谢您的建议。

我的最新代码

using namespace cv;
using namespace std;


void onMouse(int evt, int x, int y, int flags, void* param) {
    if(evt == CV_EVENT_LBUTTONDOWN) {
        std::vector<cv::Point>* ptPtr = (std::vector<cv::Point>*)param;
        ptPtr->push_back(cv::Point(x,y));
    }
}

int main()

{
std::vector<Point> points;

cv::namedWindow("Output Window");

Mat frame = cv::imread("chhha.png");

cv::setMouseCallback("Output Window", onMouse, (void*)&points);
int X=0, Y=0; 


while(1)
{
    cv::imshow("Output Window", frame);

X=points[0].x; 
Y=points[0].y; 

cout<<"First X and Y coordinates are given below"<<endl;
cout<<X<<'\t'<<Y<<endl; 


    waitKey(10);
}


getch(); 

}

这有两个主要问题:

1- 这可以很好地编译,但在运行时它会给出Debug Assertion Failed! 错误,

当我通过放置断点进行调试时,在以下几行:

X=points[0].x; 
Y=points[0].y; 

它进一步说:

表达式:向量下标超出范围

2- 如何退出 while 循环? 在其他类似的程序中,我注意到它永远保持在 while 循环中。

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    我建议不要传递给cv::Point*,而是传递std::vector&lt;cv::Point&gt;*。由于cv::Point 有一个复制构造函数,您可以通过push_back 在其中存储点。

    我的意思是代码:

    std::vector<cv:Point> points;
    cv::namedWindow("Output Window");
    
    Mat frame = cv::imread("chhhha.png");
    
    cv::setMouseCallback("Output Window", onMouse, (void*)&points);
    int X, Y; 
    
    while(1)
    {
        cv::imshow("Output Window", frame);
    
        if (points.size() > 2) //we have 2 points
        {
            for (auto it = points.begin(); it != points.end(); ++it)
            {
    
                cout<<"X and Y coordinates are given below"<<endl;
                cout<<(*it).x<<'\t'<<(*it).y<<endl; 
            }
            //draw points
        }
    ...
    

    在回调中:

    void onMouse(int evt, int x, int y, int flags, void* param) {
        if(evt == CV_EVENT_LBUTTONDOWN) {
            std::vector<cv::Point>* ptPtr = (std::vector<cv::Point>*)param;
            ptPtr->push_back(cv::Point(x,y));
        }
    }
    

    稍后,您可以使用points[0]points[1] 访问前2 个点。

    编辑:通过检查矢量大小更新了代码。您应该注意,如果鼠标回调在不同的线程中执行,则此方法可能需要锁定。

    【讨论】:

    • 太棒了!唯一的事情是现在我可以存储这些值并在 while 循环之外访问。像这样:X1=points[0].x; X2=points[1].x 等等。这是我的主要困难。
    • 您完全可以做到这一点!试试看。请记住,您必须确保您有足够的积分。例如,运行 while 循环直到 points.size() &gt; 2,然后是 break。然后就可以访问了。
    • 我想我要让它发挥作用。但是我仍然被困在while循环中。如何退出 while 循环,然后返回控制台并打印我的值?
    • 我休息一下;在 for 循环中。它工作得很好。谢谢(有一个小问题,如果一段时间后我“不响应错误”,它会挂起,我会在另一个问题中问。非常感谢您的帮助)
    猜你喜欢
    • 2014-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多