You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Qt5中通过OpenCV视频捕获获取树莓派摄像头的最新帧

树莓派CSI摄像头OpenCV读取旧帧问题解决方案

根因

树莓派CSI摄像头默认使用的V4L2驱动底层会预存2-3帧数据到内核缓冲队列,OpenCV默认的VideoCapture逻辑会优先读取队列中的旧帧,和USB摄像头的驱动缓冲逻辑存在差异,仅设置CAP_PROP_BUFFERSIZE为1无法完全清空驱动层预存的旧帧。

修复步骤

  • 打开VideoCapture时主动指定V4L2后端,避免OpenCV自动匹配到GStreamer等其他后端导致缓冲参数不生效
  • 打开成功后第一时间设置缓冲区大小为1,不要先执行read操作
  • 设置缓冲完成后连续读取3次帧并丢弃,清空驱动层预存的旧帧
  • 实时性要求极高的场景,每次获取最新帧前都先连续丢弃2帧,再读取的就是当前最新帧

修改后完整代码

#include <opencv2/videoio.hpp>
// 其他项目依赖头文件

QScopedPointer<cv::VideoCapture> videoCapture_;
cv::Mat CaptureImage;

// 摄像头初始化逻辑
videoCapture_.reset(new cv::VideoCapture(0, cv::CAP_V4L2)); // 明确指定V4L2后端
if (videoCapture_->isOpened())
{
    // 打开后第一时间设置缓冲区大小为1
    videoCapture_->set(cv::CAP_PROP_BUFFERSIZE, 1);
    // 可按需设置摄像头帧率,根据硬件实际支持参数调整
    videoCapture_->set(cv::CAP_PROP_FPS, 30);
    
    // 清空驱动层预存的旧帧
    cv::Mat temp;
    for(int i = 0; i < 3; i++) {
        videoCapture_->read(temp);
    }
    
    // 此时读取到的即为最新帧
    videoCapture_->read(CaptureImage);
}

// 循环取帧场景下的实时读帧逻辑
void getLatestFrame() {
    // 每次取最新帧前先丢2帧清空缓冲
    cv::Mat temp;
    for(int i = 0; i < 2; i++) {
        videoCapture_->read(temp);
    }
    videoCapture_->read(CaptureImage);
    // 后续帧处理逻辑
}

注意:树莓派Bullseye及以上版本系统默认使用libcamera驱动,需要先执行sudo raspi-config,在Interface Options中开启Legacy Camera支持并重启,否则V4L2后端无法正常识别CSI摄像头。

内容的提问来源于stack exchange,提问作者G Balaji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 01:06:04