我想使用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;
}
}
答案 0 :(得分:2)
绘制成一个单独的图像,然后cvAdd()在显示之前立即将其添加到视频图像
答案 1 :(得分:1)
我不会详细说明为什么你的方法很糟糕,但请记住,为绘图创建2个额外的框架有点太多了。
重要的是你要意识到所有这些 kinky stuff 都是在用于捕获新帧的同一个线程上完成的。这究竟是什么意思?这意味着您在循环中添加的额外代码将减慢捕获和显示新帧的过程。换句话说,您通过降低应用程序的帧速率来破坏自己。如果你不在乎,那没关系。如果你这样做,我的建议是你将捕获的帧堆叠到一个缓冲区中,让另一个线程读取,处理并显示它们。
好的,所以你真的想要绘制显示捕获帧的窗口。好吧,显而易见的事情你做不到(你自己发现了这个)就是无法在捕获的帧上绘制图形,因为它在每个循环中都被新数据替换。所以你会怎么做?您创建第二帧以进行绘制。我们称之为 drawing_frame 。
drawing_frame 上唯一的东西是当鼠标在窗口上移动时,当点击鼠标的LBUTTON时出现的圆圈(第二次点击在ON / OFF之间切换) )。
在绘制圆圈后, drawing_frame 会叠加在相机拍摄的帧的顶部。这个过程在CPU上有点贵,而且由于我们在应用程序的主线程中执行它,它也会降低帧速率。
我强烈建议所有对使用OpenCV添加/合并/覆盖透明帧感兴趣的人都会看一下Transparent image overlays in 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;
}
答案 2 :(得分:0)
你通常会遇到添加图像的问题(它们最终会饱和),所以我想这就是你重新开始的原因。我看到你有彩色图像...如果你为你的绘图使用更强大的东西,比如OpenGL,你可以使用叠加层来绘制图纸。否则请检查:
http://aishack.in/tutorials/transparent-image-overlays-in-opencv/