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

Capturing camera image with v4l2 very slow

我一直致力于直接使用 v4l2 在 OpenCV 中抓取相机图像。这工作得很好;这样我就可以抓取 YUYV 格式的高分辨率图像(理解帧率会下降)。我无法通过 OpenCV 实现来完成这项工作。从功能上讲,它工作得很好,但性能可能会好得多。由于这是我第一次直接使用 v4l2,所以对我来说还是有点模糊。 我一直在为所有相关部分计时,发现 v4l2 select 方法花费的时间超过一秒。当我降低时间间隔时,select 方法花费的时间更少,但比出队花费的时间长得多(也是那一秒)。在其他功能中,相机被初始化,因此设置正确的格式等。我知道帧率会很低,没有压缩和高分辨率,但这是极低的。

下面是截图功能。我跳过了将缓冲区转换为 Mat (YUYV -> RGB) 的代码,因为我认为它现在不相关。

有人知道如何使 v4l2 捕获图像更快吗?也许有些部分我不应该在每次抓帧时执行?

谢谢!

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;
}

//转换为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;
}

您似乎在调用 VIDIOC_STREAMONVIDIOC_STREAMOFF 的每一帧;这增加了很多开销(这几乎就像为每一帧重新启动您的应用程序)

正确的方法是:

  • 打开设备(只调用一次):在您的捕获会话开始时(例如程序启动),设置您的视频设备以启动通过调用 VIDIOC_STREAMON

  • 进行流式传输
  • 捕获帧(多次调用):对于要捕获的每个帧,仅通过调用DQBUF/[=来请求帧14=](这非常快,因为设备会连续 stream 数据进入缓冲队列);您仍然需要调用 select 才能知道新框架何时可用。

  • 关闭设备(仅调用一次):完成后,通过调用VIDIOC_STREAMOFF

    [=36 停止流式传输=]