YCBCR_420_888转RAW10的正确方法及RAW10尺寸计算咨询
YCbCr420_888转RAW10的可行性与问题修正
一、核心问题:转换可行性
YCbCr420_888是经过色彩插值、白平衡、伽马校正等后期处理的成品色彩格式,而RAW10是相机传感器直接输出的原始数据——每个像素对应传感器拜耳阵列上的一个单色感光单元,存储的是未经过任何色彩处理的光电信号。
两者本质完全不同:你无法从成品YCbCr还原出真实的RAW10数据,因为YCbCr已经丢失了传感器原始信息(比如拜耳阵列的单通道感光值、原生增益、暗电流等)。你能做的只是模拟一个符合RAW10文件格式的文件,但这和真实相机输出的RAW不是一回事。
二、RAW10的正确尺寸计算
RAW10采用紧凑打包存储:每4个10bit像素打包成5个字节(4×10bit=40bit=5字节),总字节数的正确计算方式为:
// 方法1:按总比特数向上取整转字节 size_t total_bytes = ((width * height * 10) + 7) / 8; // 方法2:按4像素打包的规则计算(更精准) size_t total_bytes = ((width * height) + 3) / 4 * 5;
你之前的计算都不符合RAW10的存储规则:
width * height:仅为8bit单通道的字节数,RAW10每个像素占1.25字节,完全错误width * height * 5 / 2:每个像素按2.5字节计算,是RAW10的2倍width * height * sizeof(uint16_t):按16bit/像素存储,浪费了6bit空间,不是RAW10的紧凑格式
三、你的转换函数的错误分析
- 存储结构完全错误:RAW10是拜耳阵列的单通道10bit像素打包,而非Y/Cb/Cr通道分离存储,你直接把Y按8bit、Cb/Cr按16bit拼接,完全不符合RAW10格式规范。
- 色彩模型混淆:RAW10没有Y/Cb/Cr的概念,硬塞三个通道的数据必然导致色彩错位(你看到的紫丁香色就是Cb/Cr通道错位的结果)。
- 尺寸分配错误:未按RAW10的正确字节数初始化
dst_raw,导致数据溢出或空白区域。
四、模拟生成RAW10格式文件的正确思路
如果只是需要生成符合RAW10格式的文件(而非真实传感器RAW),可以按以下步骤操作:
- 将YCbCr420转换为RGB:使用标准YCbCr转RGB公式:
uint8_t y = yPlane[y_idx * width + x_idx]; uint8_t cb = cbPlane[(y_idx/2) * (width/2) + (x_idx/2)]; uint8_t cr = crPlane[(y_idx/2) * (width/2) + (x_idx/2)]; int r = y + 1.402 * (cr - 128); int g = y - 0.344136 * (cb - 128) - 0.714136 * (cr - 128); int b = y + 1.772 * (cb - 128); // 钳位到0-255 r = std::clamp(r, 0, 255); g = std::clamp(g, 0, 255); b = std::clamp(b, 0, 255); - 模拟拜耳阵列排列:选择常见的拜耳模式(比如RGGB),每个像素位置取对应的RGB通道值,扩展为10bit(8bit值左移2位,高2位补0):
uint16_t raw_val; if ((y_idx % 2 == 0 && x_idx % 2 == 0) || (y_idx % 2 == 1 && x_idx % 2 == 1)) { // G通道位置 raw_val = (uint16_t)g << 2; } else if (y_idx % 2 == 0 && x_idx % 2 == 1) { // R通道位置 raw_val = (uint16_t)r << 2; } else { // B通道位置 raw_val = (uint16_t)b << 2; } - 按RAW10规则打包字节:每4个10bit像素打包为5个字节:
// 初始化dst_raw为正确尺寸 dst_raw.resize(total_bytes, 0); size_t byte_idx = 0; std::vector<uint16_t> raw_values(width * height); // 先填充raw_values数组(省略拜耳填充逻辑) for (int i = 0; i < width * height; i += 4) { // 获取4个连续的10bit值 uint16_t p0 = raw_values[i]; uint16_t p1 = (i+1 < width*height) ? raw_values[i+1] : 0; uint16_t p2 = (i+2 < width*height) ? raw_values[i+2] : 0; uint16_t p3 = (i+3 < width*height) ? raw_values[i+3] : 0; // 打包成5个字节 dst_raw[byte_idx++] = (p0 >> 2) & 0xFF; // p0高8位 dst_raw[byte_idx++] = (p1 >> 2) & 0xFF; // p1高8位 dst_raw[byte_idx++] = (p2 >> 2) & 0xFF; // p2高8位 dst_raw[byte_idx++] = (p3 >> 2) & 0xFF; // p3高8位 dst_raw[byte_idx++] = ((p0 & 0x03) << 6) | ((p1 & 0x03) << 4) | ((p2 & 0x03) << 2) | (p3 & 0x03); }
注意事项
- 模拟的RAW10文件仅能满足格式兼容需求,无法达到真实相机RAW的动态范围和色彩还原能力。
- 部分RAW10格式要求行对齐(比如每行字节数为16的倍数),需要在每行末尾补充填充字节。
内容的提问来源于stack exchange,提问作者Milana
相关产品推荐
相关产品推荐

