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

OpenCV: Storing the coordinates of the points clicked by mouse left button

本文关键字:坐标 存储 鼠标 OpenCV      更新时间:2023-10-16

下面的程序将给出鼠标左键点击的位置。

 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坐标存储在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; 

它进一步说:

表达式:Vector下标out of range

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

我建议传递给std::vector<cv::Point>*而不是传递给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]访问前两个点。

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