如何在OpenCV C ++中从实时视频源在框架上画一条线

时间:2019-06-11 09:16:46

标签: c++ opencv line

我想在c ++中的opencv框架上画一条线。为此,我在下面的代码中使用了setMouseCallback(winName, onMouse, NULL);。在下面的代码中,我正在使用图片:

Mat src;
const char* winName = "Image";
int start_x = 0;
int start_y = 0;
bool run_once = false;

void onMouse(int event, int x, int y, int f, void*) 
{

    if (cv::EVENT_LBUTTONDOWN)
    {
        if (f == 1)
        {
            if (run_once == false)
            {
                start_x = x;
                start_y = y;
                cout << "start x,y is : " << x << y << endl;
                run_once = true;

            }
        }
        if (f == 3)
        {
            cout << "start x,y is : " << start_x << start_y << endl;
            int end_x = x;
            int end_y = y;
            cout << "end x,y  is : " << end_x << end_y << endl;
            cv::line(src, cv::Point(start_x, start_y), cv::Point(end_x, end_y), Scalar(255), 2, 8, 0);
            imshow(winName, src);
            run_once = false;
        }


    }
}

int main()
{
    src = imread(<img path>, 1);

    namedWindow(winName, WINDOW_NORMAL);
    setMouseCallback(winName, onMouse, NULL);
    imshow(winName, src);
    while(1)
    {


    }

}

使用上述代码,如果我在框架上使用鼠标左键单击,它将记录start_x start_y。我向左/右拖动鼠标,然后单击鼠标右键,它会记录end_x end_y并简单地画一条线并显示它。效果很好,但我想在实时视频帧中实现此功能。

我在直播视频帧中面临的问题是,在直播视频供稿中,我们不断在while(1)循环中显示帧,因此在下一帧中删除了画出的线条

void onMouse(int event, int x, int y, int f, void*)
{
   /*
    * SAME AS ABOVE
    */
}

int main(int, char**)
{
    VideoCapture cap(1); // open the default camera
    if (!cap.isOpened())  // check if we succeeded
        return -1;
    namedWindow(winName, WINDOW_NORMAL);
    setMouseCallback(winName, onMouse, NULL);


    for (;;)
    {

        cap >> src; // get a new frame from camera
        imshow(winName, src);
        if (waitKey(30) >= 0) break;
    }
    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}

在上面的代码中,我们具有onMouse函数,其中我们使用imshow来显示框架上绘制的线条,但我们在imshow循环中也有while(1),因此未显示绘制的线条

无论如何,我可以在实时视频供稿框架上画线。请帮忙。谢谢

1 个答案:

答案 0 :(得分:1)

按照@Sunreef的建议,您可以创建单独的cv::Mat以仅保留行的图片,并显示src与该图片组合在一起

// #0 NEW - add declaration of lines here so this Mat is visible in both onMouse and main scope
cv::Mat src, lines;

void onMouse(int event, int x, int y, int f, void*)
{        
    if (f == 3)
    {
        cout << "start x,y is : " << start_x << start_y << endl;
        int end_x = x;
        int end_y = y;
        cout << "end x,y  is : " << end_x << end_y << endl;

        // #1 NEW - draw line into lines instead of src
        cv::line(lines, cv::Point(start_x, start_y), cv::Point(end_x, end_y), Scalar(255), 2, 8, 0);

        // #2 NEW - remove unnecessary imshow here

        run_once = false;
     }
}

int main(int, char**)
{
    for (;;)
    {
        cap >> src; 

        // #3 NEW - init lines once, to be the same size, same type as src filled with zeros
        if(lines.empty()) lines = cv::Mat::zeros(src.size(), src.type());

        // #4 NEW - show lines combined with lines            
        imshow(winName, lines + src);

        if (waitKey(30) >= 0) break;
    }
    return 0;
}

这样,lines中只有onMouse的图像被更新(#1)。无需在onMouse事件(#2)中显示它,因为它将始终在主循环(#4)中显示。但是,在实际显示行之前,您需要将其覆盖(添加)到src图像中。唯一棘手的部分是一旦知道lines(#3)的大小和类型就初始化src。并且请记住先声明lines(#0),以便图像像src一样在全局可见。

我还建议您熟悉: