简体   繁体   English

使用v4l2捕获相机图像非常慢

[英]Capturing camera image with v4l2 very slow

I've been working on using v4l2 directly to grab a camera image in OpenCV. 我一直在努力使用v4l2直接在OpenCV中抓取相机图像。 This is working very nice; 这工作得非常好; this way I can grab an image in YUYV format and with a high resolution (understanding that the framerate will drop). 通过这种方式,我可以以YUYV格式和高分辨率获取图像(了解帧速率将下降)。 I couldn't get this done with the OpenCV implementation. 我无法通过OpenCV实现完成这项工作。 Functionally it's working great, but the performance could be much better. 功能上它的工作效果很好,但性能可能会好得多。 Since this is my first time using v4l2 directly, it's still a bit vague to me. 由于这是我第一次直接使用v4l2,它对我来说仍然有点模糊。 I've been timing all relevant parts and saw that the v4l2 select method is taking a bit more than a second. 我已经对所有相关部分进行了计时,并发现v4l2选择方法需要花费一秒多的时间。 When I lower the timeinterval, the select method takes less time, but than the dequeueing takes much longer (also that second). 当我降低时间间隔时,select方法花费的时间更少,但是出列的时间要长得多(也就是第二次)。 In other funtions the camera is initialised, so setting the right format etc. I understand that the framerate will be low, with no compression and high resolution, but this is extreamly low. 在其他功能中,相机被初始化,因此设置正确的格式等。我知道帧速率很低,没有压缩和高分辨率,但这是极低的。

Below is the capture image function. 下面是捕获图像功能。 I skipped the code in which the buffer is transformed to a Mat (YUYV -> RGB), because I think that it's not relevant for now. 我跳过了缓冲区转换为Mat(YUYV - > RGB)的代码,因为我认为它现在不相关。

Does anybody know how to make v4l2 capture images much faster? 有谁知道如何使v4l2捕获图像更快? Maybe there are parts that I should not perform each frame grab? 也许有些部分我不应该执行每个帧抓取?

Thank you! 谢谢!

Mat Camera::capture_image() {
Mat returnframe(10, 10, CV_8UC3);
struct v4l2_buffer buf = {0};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
    perror("Query Buffer");
    return returnframe;
}

if (-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type)) {
    perror("Start Capture");
    return returnframe;
}

fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval tv = {0};
tv.tv_sec = 2;
int r = select(fd + 1, &fds, NULL, NULL, &tv);
if (-1 == r) {
    perror("Waiting for Frame");
    return returnframe;
}

if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
    perror("Retrieving Frame");
    return returnframe;
}

//code here for converting to Mat //这里的代码转换为Mat

if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &buf.type)) {
    perror("Stop Capture");
    return returnframe;
}

//copy Mat and free bigbuffer, to avoid memory leak
Mat returnImg = dispimg.clone();
free(bigbuffer);
return returnImg;
}

it seems that for each frame you are calling VIDIOC_STREAMON and VIDIOC_STREAMOFF ; 似乎每个帧都调用VIDIOC_STREAMONVIDIOC_STREAMOFF ; this adds a lot of overhead (it's almost like re-starting your application for each frame) 这会增加很多开销(这几乎就像为每个帧重新启动应用程序一样)

the proper way would be: 正确的方法是:

  • open device (called only once): at the beginning of your capture-session (eg the program start), setup your video-device to start streaming by calling VIDIOC_STREAMON 打开设备 (仅调用一次):在捕获会话开始时(例如程序启动),通过调用VIDIOC_STREAMON设置视频设备以开始流式传输

  • capture frame (called multiple times): for each frame you want to capture, request the frame by only calling DQBUF / QBUF (this is pretty fast, as the device will continuously stream data into the buffer queue); 捕获帧 (多次调用):对于要捕获的每个帧,仅通过调用DQBUF / QBUF请求帧(这非常快,因为设备将连续地将数据传输到缓冲区队列中); you will still need to call select in order to know when a new frame is available. 您仍然需要调用select才能知道新帧何时可用。

  • close device (called only once): once you are done, stop streaming by calling VIDIOC_STREAMOFF 关闭设备 (仅调用一次):完成后,通过调用VIDIOC_STREAMOFF停止流式传输

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM