如何从BMP文件恢复双目相机原始YUYV缓冲区数据?
问题根源
你的核心问题是:cv2.VideoCapture.read()默认会自动将相机输出的YUYV格式数据流转换为BGR图像,所以你保存的BMP文件已经是转换后的RGB类数据,而非原始的YUYV缓冲区,自然无法恢复出两个传感器的原始图像。
解决方案
要获取并保存原始YUYV缓冲区,需要跳过OpenCV的自动格式转换,直接读取原始字节流并以二进制格式存储,之后再按YUYV结构解析。
步骤1:配置相机读取原始YUYV数据
修改相机参数,强制读取原始YUYV格式,避免自动转换:
import cv2 import os cap = cv2.VideoCapture(0) # 设置相机输出格式为YUYV(fourcc码为0x56595559) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('Y','U','Y','V')) # 可选:验证格式是否设置成功 print(f"当前相机输出格式fourcc: {hex(int(cap.get(cv2.CAP_PROP_FOURCC)))}") if not cap.isOpened(): raise IOError("无法打开相机") i = 0 folder = os.path.dirname(os.path.realpath(__file__))
步骤2:保存原始YUYV缓冲区为二进制文件
不要使用cv2.imwrite(它会对图像数据做编码转换),直接将原始字节流写入二进制文件:
while True: # 用retrieve直接获取原始YUYV帧,比read更可靠 ret, raw_yuyv_frame = cap.retrieve(cv2.CAP_MODE_YUYV) if not ret: break # 缩小后预览(可选) preview = cv2.resize(raw_yuyv_frame[:, ::2], None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA) cv2.imshow('预览', preview) c = cv2.waitKey(1) if c == 27: # ESC退出 break if c == 13: # Enter保存 # 写入二进制.raw文件,完整保留原始缓冲区 with open(os.path.join(folder, f"{i:04d}.raw"), 'wb') as f: f.write(raw_yuyv_frame.tobytes()) i += 1 cap.release() cv2.destroyAllWindows()
步骤3:读取原始YUYV文件并解析两个传感器图像
根据YUYV的格式结构(每4字节对应2个像素:Y0 U Y1 V),提取对应两个传感器的通道:
import numpy as np import cv2 def parse_yuyv_raw(file_path, width, height): # 读取原始二进制数据 raw_data = np.fromfile(file_path, dtype=np.uint8) # 重构为YUYV格式的二维数组(每行包含width*2字节,对应width个像素) yuyv_frame = raw_data.reshape((height, width * 2)) # 提取第一个传感器的图像:所有Y分量(每行的第0、2、4...字节) sensor1_img = yuyv_frame[:, ::2] # 提取第二个传感器的图像:U分量(每行的第1、5、9...字节),需放大到与Y通道同尺寸 sensor2_u = yuyv_frame[:, 1::4] sensor2_img = np.repeat(sensor2_u, 2, axis=1) # 每个U对应2个Y像素,横向重复补全 return sensor1_img, sensor2_img # 替换为你的相机实际分辨率 sensor1, sensor2 = parse_yuyv_raw("0000.raw", 640, 480) # 显示两个传感器的原始图像 cv2.imshow("传感器1(Y通道)", sensor1) cv2.imshow("传感器2(U通道)", sensor2) cv2.waitKey(0) cv2.destroyAllWindows()
关键说明
cv2.CAP_MODE_YUYV是OpenCV指定读取原始YUYV流的模式,确保拿到未转换的原始缓冲区。- 二进制
.raw文件完全保留相机输出的原始字节数据,没有任何格式转换损耗。 - 解析时需根据相机设计(Y对应一个传感器,U/V对应另一个)提取通道,若V通道对应第二个传感器,只需把代码中的
1::4改为3::4即可。
内容的提问来源于stack exchange,提问作者Cookie
相关产品推荐
相关产品推荐

