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

如何用C++结合OpenCV将.img文件转换为HEVC/H.265文件

基于OpenCV(C++)实现相机原始IMG转HEVC流媒体压缩方案

相机直接输出的.img基本都是无封装的裸帧数据,没有文件头、元信息,转换前必须先确认文件对应的单帧分辨率、像素格式、位深、帧率参数,否则无法正确解析帧内容。

前置依赖要求

  • 编译/安装OpenCV时必须开启FFmpeg支持,且关联的FFmpeg必须编译集成libx265编码库,否则OpenCV无法调用HEVC编码能力。Linux下编译OpenCV时需打开-DWITH_FFMPEG=ON选项,提前装好libx265-dev依赖;Windows可直接选用集成了FFmpeg+x265的预编译contrib版本。
  • 提前确认.img文件的单帧参数:比如1920*1080分辨率、8位BGR格式的裸帧,单帧固定大小为1920*1080*3字节,逐帧连续存储在文件中。

实现逻辑

  1. 二进制方式读取原始IMG文件:因为是裸流,无法直接通过VideoCapture加载,按单帧固定字节长度逐块读入内存,转换为OpenCV的Mat结构即可。
  2. 初始化HEVC编码器:通过VideoWriter创建编码实例,FOURCC标识根据编译的编码器选择,Windows下一般用H265,跨平台x265场景可尝试hvc1/hev1标识。针对流媒体传输场景,要针对性调编码参数:CRF值设23-28(数值越高压缩率越高、质量越低,26-28是公网流媒体常用的带宽友好值),码率按分辨率匹配,1080p30fps设2-4Mbps即可,编码预设选快速档位降低延迟。
  3. 逐帧编码输出:每读入一帧做必要的像素格式转换(比如RGB转BGR、YUV转BGR)后写入编码器,所有帧处理完成后释放资源即可得到可直接用于流媒体传输的HEVC文件,也可直接输出到RTMP/RTSP推流地址实现边编码边推流。

参考实现代码

#include <opencv2/opencv.hpp>
#include <fstream>
#include <iostream>

int main() {
    // 以下参数请根据自身.img文件实际属性修改
    const std::string raw_img_path = "camera_record.img";
    const std::string output_hevc_path = "stream_hevc.mp4";
    const int frame_w = 1920;
    const int frame_h = 1080;
    const int fps = 30;
    // 单帧字节数:8位BGR/RGB为 w*h*3,单通道灰度为w*h,YUV420为w*h*3/2
    const size_t frame_bytes = frame_w * frame_h * 3;

    // 打开原始裸帧文件
    std::ifstream raw_fp(raw_img_path, std::ios::binary);
    if (!raw_fp.is_open()) {
        std::cerr << "打开原始img文件失败,请检查路径" << std::endl;
        return -1;
    }

    // 初始化HEVC编码器
    int hevc_fourcc = cv::VideoWriter::fourcc('H', '2', '6', '5');
    cv::VideoWriter encoder;
    encoder.open(output_hevc_path, hevc_fourcc, fps, cv::Size(frame_w, frame_h), true);
    if (!encoder.isOpened()) {
        // 如果H265标识初始化失败,替换为hvc1/hev1重试
        std::cerr << "HEVC编码器初始化失败,请检查OpenCV是否集成x265支持" << std::endl;
        return -1;
    }

    // 流媒体场景编码参数调优
    encoder.set(cv::VIDEOWRITER_PROP_QUALITY, 70); // 质量70对应CRF约26,兼顾画质和带宽
    encoder.set(cv::VIDEOWRITER_PROP_BITRATE, 3000000); // 目标码率3Mbps,可按带宽调整

    // 逐帧读取编码
    char* frame_buf = new char[frame_bytes];
    cv::Mat frame(frame_h, frame_w, CV_8UC3);
    while (raw_fp.read(frame_buf, frame_bytes)) {
        memcpy(frame.data, frame_buf, frame_bytes);
        // 若原始帧为RGB顺序,需打开下面这行做格式转换
        // cv::cvtColor(frame, frame, cv::COLOR_RGB2BGR);
        // 若原始帧为YUV格式,需对应转成BGR后再写入编码器
        encoder.write(frame);
    }

    // 资源释放
    delete[] frame_buf;
    raw_fp.close();
    encoder.release();
    std::cout << "转换完成,输出文件:" << output_hevc_path << std::endl;
    return 0;
}

常见问题说明

  • 部分工业相机会在.img文件开头写入固定长度的设备信息头,读取时需要先跳过对应长度的字节再开始读帧,否则会出现首帧花屏、帧错位的问题。
  • 流媒体场景不要开启无损HEVC编码,压缩率极低无法节省带宽,CRF值不建议低于22,避免码率波动过大导致传输卡顿。
  • 如果需要满足实时推流的低延迟要求,可开启GPU硬编码(OpenCV的cudacodec模块支持NVENC的HEVC硬编码),编码速度比CPU软编快5-10倍,延迟可降到百毫秒级。
  • 若需要直接推流无需存本地文件,可将output_hevc_path替换为支持的流媒体地址(比如RTMP推流地址),FFmpeg支持的协议都可直接写入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:54:15