4. 数据采集

任务目标

本案例实现车载摄像头视频流采集,完成从摄像头设备读取帧数据、解码并保存为图像文件的全过程。采集结果将作为后续AI模型推理的数据来源,因此需要保证帧率稳定且图像格式统一。

环境与依赖

  • 硬件:USB摄像头或CSI接口摄像头(本案例以V4L2接口为例)
  • 操作系统:Linux(Ubuntu 20.04+)
  • 依赖库:OpenCV(≥4.2)、V4L2内核驱动
  • 安装命令:sudo apt install libopencv-dev v4l-utils

核心实现

以下代码实现从摄像头采集视频流,逐帧读取并保存为JPEG图像。代码包含设备初始化、帧采集循环、异常退出处理和资源释放,可直接编译运行。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <ctime>
#include <sys/stat.h>

int main() {
    // 打开摄像头设备(0为默认摄像头,可改为/dev/video1等)
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        std::cerr << "错误:无法打开摄像头设备" << std::endl;
        return -1;
    }

    // 设置采集参数:分辨率1280x720,帧率30fps
    cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
    cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
    cap.set(cv::CAP_PROP_FPS, 30);

    // 创建保存目录
    mkdir("captured_frames", 0777);

    cv::Mat frame;
    int frame_count = 0;
    const int MAX_FRAMES = 100;  // 采集100帧后自动停止

    std::cout << "开始采集,共采集 " << MAX_FRAMES << " 帧..." << std::endl;

    while (frame_count < MAX_FRAMES) {
        // 读取一帧
        cap >> frame;
        if (frame.empty()) {
            std::cerr << "警告:读取空帧,跳过" << std::endl;
            continue;
        }

        // 生成带时间戳的文件名
        char filename[128];
        time_t now = time(nullptr);
        struct tm *tm_info = localtime(&now);
        strftime(filename, sizeof(filename), 
                 "captured_frames/frame_%Y%m%d_%H%M%S_%03d.jpg", tm_info, frame_count);

        // 保存为JPEG(质量95)
        std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 95};
        bool saved = cv::imwrite(filename, frame, params);
        if (!saved) {
            std::cerr << "错误:保存图像失败 " << filename << std::endl;
            break;
        }

        frame_count++;
        if (frame_count % 10 == 0) {
            std::cout << "已采集 " << frame_count << " 帧" << std::endl;
        }
    }

    cap.release();
    std::cout << "采集完成,共保存 " << frame_count << " 帧图像到 captured_frames/ 目录" << std::endl;
    return 0;
}

编译与运行

# 编译
g++ -o frame_capture frame_capture.cpp $(pkg-config --cflags --libs opencv4)

# 运行(需要摄像头权限)
./frame_capture

验证方法

  1. 运行程序后,终端输出“开始采集”提示,每10帧打印一次进度;
  2. 程序结束后,检查当前目录下是否生成captured_frames/文件夹;
  3. 进入文件夹执行 ls | wc -l,确认文件数量为100;
  4. 随机打开一张图片(如 eog frame_*.jpg),确认图像内容清晰、无花屏或绿屏;
  5. 使用 file frame_*.jpg | head -1 检查文件格式,应显示 JPEG image data。

常见问题

  • 摄像头无法打开:检查设备节点 ls /dev/video*,若权限不足执行 sudo usermod -a -G video $USER 后重新登录;
  • 图像全黑或花屏:尝试降低分辨率至640x480,或检查摄像头是否被其他进程占用(sudo fuser /dev/video0);
  • 帧率不稳定:USB摄像头受带宽限制,可关闭自动曝光(v4l2-ctl -c exposure_auto=1)提升稳定性。