使用OpenCV在网络摄像头上绘制图像

7
我希望能够在使用OpenCV的摄像头屏幕上进行绘画。由于我正在从摄像头读取数据,因此帧率不断变化,所以我正在尝试找到一种方法来保留或保存当前帧上的绘画,并将其用于下一帧。以下代码允许您在屏幕上绘制,但当它获取下一帧时,绘画就会消失并重新开始。
请问有人可以帮助我吗?谢谢。
          CvCapture *input;
          input = cvCaptureFromCAM( 0 );

          cvSetMouseCallback("Demo",&on_mouse, 0);

                 for(;;)
                    {
                        frame = cvQueryFrame(input);

                        if(!image)
                        {
                            image = cvCreateImage( cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3);
                            screenBuffer = cvCreateImage( cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3);
                        }

                        cvCopy(frame, image, 0);

                        if(drawing) //drawing is a global variable
                        { 
                           cvCircle(image, cvPoint(last_x,last_y), 10,CV_RGB(red,green,blue), -1, CV_AA, 0);
                           cvCopy(image, screenBuffer, 0);
                        }

                        cvShowImage( "Demo", screenBuffer );
                }


        void on_mouse( int event, int x, int y, int flags, void* param )
        {
            last_x = x;
            last_y = y;

            if(event==CV_EVENT_LBUTTONDOWN)
                {
                    drawing = 1;
                }
        }

与我的兴趣相关。您能否在评论中发布您正在使用的文档/教程?我想在OpenCV中开始学习。谢谢。 - sdadffdfd
我们非常重视您审查问题并接受解决您问题的答案。 - karlphillip
3个回答

2

在显示视频图像之前,将其绘制到单独的图像中,然后使用cvAdd()函数将该图像添加到视频图像中。


1

我不会详细解释为什么你的方法不好,但请记住,为绘图创建2个额外的帧有点过多。

重要的是,您意识到所有这些“奇怪的东西”都是在用于捕获新帧的同一线程上完成的。这意味着什么?这意味着您在循环内添加的额外代码将减慢捕获和显示新帧的过程。换句话说,通过降低应用程序的帧速率,您正在自我破坏。如果您不在意,那没关系。如果您在意,我的建议是将捕获的帧堆叠到缓冲区中,并使用另一个线程读取、处理和显示它们。

好吧,您真的想在显示捕获帧的窗口上绘制。嗯,显然您不能在捕获帧上进行绘制(您自己也发现了这一点),因为每次循环都会用新数据替换该帧。那么你该怎么办?您可以创建第二个帧来进行绘制。我们称之为“绘图帧”。

drawing_frame 上唯一的东西就是当鼠标在窗口上移动时出现的圆圈,当鼠标的 LBUTTON 被点击时(第二次点击在 ON/OFF 之间切换)。

在圆圈绘制完成后,drawing_frame 覆盖在相机捕获的帧的顶部。这个过程对 CPU 来说有点昂贵,而且由于我们在应用程序的主线程中执行它,它也会降低帧速率。

我强烈建议所有对使用 OpenCV 添加/合并/叠加透明框架感兴趣的人看一下 OpenCV 中的透明图像叠加

顺便说一下,我正在使用 cvCaptureFromCAM(-1),因为我在 Linux 上。你可能应该将其更改为适合你的内容。根据你的帖子,它应该是 cvCaptureFromCAM(0)

#include <stdio.h>

#include <cv.h>
#include <highgui.h>

int drawing = 0;
int last_x = 0;
int last_y = 0;


void on_mouse(int event, int x, int y, int flags, void* param)
{
    last_x = x;
    last_y = y;

    if (event == CV_EVENT_LBUTTONDOWN)
    {
        // switches between On and Off
        if (drawing)
            drawing = 0;
        else
            drawing = 1;
    }
}


int main()
{
    CvCapture* capture = NULL;
    if ((capture = cvCaptureFromCAM(-1)) == NULL)
    {
        fprintf(stderr, "ERROR: capture is NULL \n");
        return -1;
    }

    cvNamedWindow("mywindow", CV_WINDOW_AUTOSIZE);

    cvQueryFrame(capture); // Sometimes needed to get correct data

    cvSetMouseCallback("mywindow",&on_mouse, 0);

    IplImage* frame = NULL;
    IplImage* drawing_frame = NULL;
    while (1)
    {
        if ((frame = cvQueryFrame(capture)) == NULL)
        {
            fprintf( stderr, "ERROR: cvQueryFrame failed\n");
            break;
        }

        if (frame == NULL)
        {
            fprintf( stderr, "WARNING: cvQueryFrame returned NULL, sleeping..\n");
            usleep(100000);
            continue;
        }

        if (!drawing_frame) // This frame is created only once
        {
            drawing_frame = cvCreateImage(cvSize(frame->width, frame->height), frame->depth, frame->nChannels);
            cvZero(drawing_frame);
        }

        if (drawing)
        {
            cvCircle(drawing_frame, cvPoint(last_x,last_y), 10,CV_RGB(0, 255, 0), -1, CV_AA, 0);

            // For overlaying (copying transparent images) in OpenCV
            // http://www.aishack.in/2010/07/transparent-image-overlays-in-opencv/
            for (int x = 0; x < frame->width; x++)
            {
                for (int y = 0; y < frame->height; y++)
                {
                    CvScalar source = cvGet2D(frame, y, x);
                    CvScalar over = cvGet2D(drawing_frame, y, x);

                    CvScalar merged;
                    CvScalar S = { 1,1,1,1 };
                    CvScalar D = { 1,1,1,1 };

                    for(int i = 0; i < 4; i++)
                        merged.val[i] = (S.val[i] * source.val[i] + D.val[i] * over.val[i]);

                    cvSet2D(frame, y, x, merged);
                }
            }
        }

        cvShowImage("mywindow", frame);

        int key = cvWaitKey(10);
        if (key  == 113) // q was pressed on the keyboard
            break;
    }

    cvReleaseImage(&frame);
    cvReleaseImage(&drawing_frame);
    cvReleaseCapture(&capture);
    cvDestroyWindow("mywindow");

    return 0;
}

@Aziz 请查看答案并接受解决您的问题的答案。 - karlphillip

0
通常你会遇到添加图像的问题(它们最终会饱和),所以我猜这就是你重新开始的原因。我看到你有彩色图像... 如果你使用更强大的东西,如OpenGL进行绘图,你可以使用叠加来进行绘制。否则请看看这个:

http://aishack.in/tutorials/transparent-image-overlays-in-opencv/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接