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

Rog*_*ier 5 c++ camera opencv v4l2

我一直在努力使用v4l2直接在OpenCV中抓取相机图像.这工作得非常好; 通过这种方式,我可以以YUYV格式和高分辨率获取图像(了解帧速率将下降).我无法通过OpenCV实现完成这项工作.功能上它的工作效果很好,但性能可能会好得多.由于这是我第一次直接使用v4l2,它对我来说仍然有点模糊.我已经对所有相关部分进行了计时,并发现v4l2选择方法需要花费一秒多的时间.当我降低时间间隔时,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;
}
Run Code Online (Sandbox Code Playgroud)

//这里的代码转换为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;
}
Run Code Online (Sandbox Code Playgroud)

uml*_*ute 6

似乎对于您正在调用的每一帧VIDIOC_STREAMON和VIDIOC_STREAMOFF; 这会增加很多开销(这几乎就像为每一帧重新启动您的应用程序)

正确的方法是:

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

  • 捕获帧(多次调用):对于您要捕获的每一帧,仅通过调用DQBUF/来请求帧QBUF(这非常快,因为设备会不断将数据流式传输到缓冲区队列中);您仍然需要调用select才能知道新框架何时可用。

  • 关闭设备(仅调用一次):完成后,通过调用停止流式传输VIDIOC_STREAMOFF

  • 不,你仍然使用`select`(知道帧什么时候准备好),`DQBUF`(*出队缓冲区*)和`QBUF`(*队列缓冲区*)属于一起(你使用*both*);关键是,你不能在 *capture frame* 函数中调用 `STREAMON`,而是在 *open device* 函数中调用。 (2认同)