OpenCV:存储鼠标左键单击的点的坐标

时间:2014-07-05 11:36:54

标签: c++ opencv

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

 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 [0]和X [1]中存储两次点击的x坐标,对于y坐标,我们会同样存储Y [0]和Y [1] 。

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

提前感谢您的建议。

我的最新代码

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循环中。

1 个答案:

答案 0 :(得分:4)

我建议不要传递给cv::Point*,而是传递std::vector<cv::Point>*。由于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个点。

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