如何用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字节,逐帧连续存储在文件中。
实现逻辑
- 二进制方式读取原始IMG文件:因为是裸流,无法直接通过
VideoCapture加载,按单帧固定字节长度逐块读入内存,转换为OpenCV的Mat结构即可。 - 初始化HEVC编码器:通过
VideoWriter创建编码实例,FOURCC标识根据编译的编码器选择,Windows下一般用H265,跨平台x265场景可尝试hvc1/hev1标识。针对流媒体传输场景,要针对性调编码参数:CRF值设23-28(数值越高压缩率越高、质量越低,26-28是公网流媒体常用的带宽友好值),码率按分辨率匹配,1080p30fps设2-4Mbps即可,编码预设选快速档位降低延迟。 - 逐帧编码输出:每读入一帧做必要的像素格式转换(比如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
相关产品推荐
相关产品推荐

