Mipiraw和unpackraw区别
传感器采集的RAW数据通常为10bit,存储RAW数据需要两个Byte,而其中有6个bit位是空着的,这样就有存储空间浪费。MIPI RAW数据充分利用了这个特性,采用5个Byte,共40bit存储4个RAW数据。大部分UnpackRaw图都是以小端模式存储,MipiRaw则是大端存储。Raw图只有数据,没有其他属性信息。
下面依次详细解释raw图存储格式 和 MSB、LSB的排列方式 以及 转换方法。
上图:
一、10Bit转换
1、大小端和MSB、LSB解释
1.1、像素示意图
.这里是左上角第一个像素值是93
.这是对应第二个像素值82
1.2、十六进制示意图
.对应MiPiRaw的十六进制
.对应UnpackRaw的十六进制
1.3、大小端判断
UnpackRaw:
从UnpackRaw的十六进制看,前两个字节为 5D 00,像素值为93,而十六进制0x5D对应的十进制就是93。从结果推理前两个字节标识的像素字节为单位排列应该是 00 5D,从而判断是小端模式存储。
小端模式:高有效位在高地址,低有效在低地址,从右向左读就是正确的数据排列。
大端模式:高有效位在低地址,低有效位在高地址,从左向右都就是正确的数据排列。
注意大小端模式以字节为单位。
MIpiRaw:
从上面MipiRaw的十六进制来看是大端模式,将两个最低有效位存储到公共字节中,如下图:
0x17 << 2 + 0x39 & 0x03 = 0x0001011101,即0x00 5D,即93
1.4、MSB和LSB的判断
首先看一张图片:
大端模式和小端模式字节内均有两种存储方式。
UnpackRaw:
从1.3的图中可以看出
UnpackRaw是小端模式 + 字节内MSB优先的存储方式
MipiRaw是大端模式 + 字节内MSB优先的存储方式
结论:UnpackRaw是小端模式 + 字节内MSB优先的存储方式。
MipiRaw是大端模式 + 字节内MSB优先的存储方式。
2、转换方法
2.1、存储示意图
10 Bpp:
Unpackraw
4个像素占用8个字节。灰色是空置未使用的bit位。
MipiRaw
4个像素占用5个字节
2.2、代码实现
代码实现将MipiRaw的排列改为UnpackRaw的排列,代码实现如下:
参数:
pIn:指源文件指针
pOut:指输出文件指针
number:指MipiRaw的像素个数,即宽*高
代码实现将MipiRaw的排列改为UnpackRaw的排列,代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
typedef unsigned char BYTE; // 定义BYTE类型,占1个字节
void MipiRaw10ToP10(BYTE* pIn, BYTE* pOut, long number)
{
printf("enter MipiRaw10ToP10\n");
int index = 0;
// 5个字节4个像素
// 前面4个字节都是对应像素的高8位,最后一个字(第五个)每个像素的低2位
// MIPIRaw 大端模式
// BYTE0 :P1[0:7]
// BYTE1 :P2[0:7]
// BYTE2 :P3[0:7]
// BYTE3 :P4[0:7]
// BYTE4 :P4[8:9]P3[8:9]P2[8:9]P1[8:9]
// UnpackRaw 小端模式
// Pix1: BYTE0:[2:9], BYTE1:[0:1] == BYTE0:(P1[0:7]<< 2 + P1[8:9]), BYTE1:(P1[0:7] >> 6)
// Pix2: 上同
// Pix3: 上同
// Pix4: 上同
// Big endian
for (long i = 0; i < (number * 5) / 4; i = i + 5)
{
pOut[index++] = ((pIn[i] << 2) & 0xfc) | (pIn[i + 4] & 0x03);
pOut[index++] = (pIn[i] >> 6) & 0x03;
//pIn[i+4] >>= 2;
pOut[index++] = ((pIn[i + 1] << 2) & 0xfc) | ((pIn[i + 4] >> 2) & 0x03);
pOut[index++] = (pIn[i + 1] >> 6) & 0x03;
//pIn[i+4] >>= 2;
pOut[index++] = ((pIn[i + 2] << 2) & 0xfc) | ((pIn[i + 4] >> 4) & 0x03);
pOut[index++] = (pIn[i + 2] >> 6) & 0x03;
//pIn[i+4] >>= 2;
pOut[index++] = ((pIn[i + 3] << 2) & 0xfc) | ((pIn[i + 4] >> 6) & 0x03);
pOut[index++] = (pIn[i + 3] >> 6) & 0x03;
}
printf("MipiRaw10ToP10 over\n");
}
二、12Bit转换
一个像素占用12个bit,两个字节空置4个bit未使用。MipiRaw则是3个字节存储两个像素,最有一些字节保留两个像素最低四位的有效位数据。
1、大小端、MSB和LSB
1.1、像素示意图
左上角第一个像素的有效值 296
左上角第二个像素有效值 312
1.2、十六进制示意图
MipiRaw:
Unpackraw:
1.3、大小端及MSB和LSB的判断
根据十六进制上示意图:
根据像素值,然后从十六进制就可以看出Unpack是小端模式。根据如上示意图,看出字节内是MSB优先。
从示意图看出,MipiRaw是大端存储方式,最低四位有效位放在公共字节。
结论:UnpackRaw是小端模式 + 字节内MSB优先的存储方式。
MipiRaw是大端模式 + 字节内MSB优先的存储方式。
2、转换方法
2.1、存储示意图
12Bpp:
UnpackRaw
2个像素占用4个字节
MipiRaw
2个像素占用3个字节
2.2代码实现
代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
typedef unsigned char BYTE; // 定义BYTE类型,占1个字节
void MipiRaw12ToP12(BYTE* pIn, BYTE* pOut, long number)
{
printf("enter MipiRaw12ToP12\n");
int index = 0;
// 3个字节2个像素
// 前面2个字节都是对应像素的高8位,最后一个字(第3个)每个像素的低4位
// MIPIRaw 大端模式
// BYTE0 :P1[0:7]
// BYTE1 :P2[0:7]
// BYTE2 :P2[8:11]P1[8:11]
// UnpackRaw 小端模式
// Pix1: BYTE0:[4:11], BYTE1:[0:3] == BYTE0:(P1[0:7]<< 4 + P1[8:11]), BYTE1:(P1[0:7] >> 4)
// Pix2: 上同
// Big endian
for (long i = 0; i < (number * 3) / 2; i = i + 3)
{
pOut[index++] = ((pIn[i] << 4) & 0xf0) | (pIn[i + 2] & 0x0f);
pOut[index++] = (pIn[i] >> 4) & 0x0f;
//pIn[i+2] >>= 4;
pOut[index++] = ((pIn[i + 1] << 4) & 0xf0) | ((pIn[i + 2] >> 4) & 0x0f);
pOut[index++] = (pIn[i + 1] >> 4) & 0x0f;
}
printf("MipiRaw12ToP12 over\n");
}
常见的还有14bit的MIPIRaw,小编就不写了,留给大家练习。
整体代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
typedef unsigned char BYTE; // 定义BYTE类型,占1个字节
void MipiRaw10ToP10(BYTE* pIn, BYTE* pOut, long number)
{
printf("enter MipiRaw10ToP10\n");
int index = 0;
// 5个字节4个像素
// 前面4个字节都是对应像素的高8位,最后一个字(第五个)每个像素的低2位
// MIPIRaw 大端模式
// BYTE0 :P1[0:7]
// BYTE1 :P2[0:7]
// BYTE2 :P3[0:7]
// BYTE3 :P4[0:7]
// BYTE4 :P4[8:9]P3[8:9]P2[8:9]P1[8:9]
// UnpackRaw 小端模式
// Pix1: BYTE0:[2:9], BYTE1:[0:1] == BYTE0:(P1[0:7]<< 2 + P1[8:9]), BYTE1:(P1[0:7] >> 6)
// Pix2: 上同
// Pix3: 上同
// Pix4: 上同
// Big endian
for (long i = 0; i < (number * 5) / 4; i = i + 5)
{
pOut[index++] = ((pIn[i] << 2) & 0xfc) | (pIn[i + 4] & 0x03);
pOut[index++] = (pIn[i] >> 6) & 0x03;
//pIn[i+4] >>= 2;
pOut[index++] = ((pIn[i + 1] << 2) & 0xfc) | ((pIn[i + 4] >> 2) & 0x03);
pOut[index++] = (pIn[i + 1] >> 6) & 0x03;
//pIn[i+4] >>= 2;
pOut[index++] = ((pIn[i + 2] << 2) & 0xfc) | ((pIn[i + 4] >> 4) & 0x03);
pOut[index++] = (pIn[i + 2] >> 6) & 0x03;
//pIn[i+4] >>= 2;
pOut[index++] = ((pIn[i + 3] << 2) & 0xfc) | ((pIn[i + 4] >> 6) & 0x03);
pOut[index++] = (pIn[i + 3] >> 6) & 0x03;
}
printf("MipiRaw10ToP10 over\n");
}
void MipiRaw12ToP12(BYTE* pIn, BYTE* pOut, long number)
{
printf("enter MipiRaw12ToP12\n");
int index = 0;
// 3个字节2个像素
// 前面2个字节都是对应像素的高8位,最后一个字(第3个)每个像素的低4位
// MIPIRaw 大端模式
// BYTE0 :P1[0:7]
// BYTE1 :P2[0:7]
// BYTE2 :P2[8:11]P1[8:11]
// UnpackRaw 小端模式
// Pix1: BYTE0:[4:11], BYTE1:[0:3] == BYTE0:(P1[0:7]<< 4 + P1[8:11]), BYTE1:(P1[0:7] >> 4)
// Pix2: 上同
// Big endian
for (long i = 0; i < (number * 3) / 2; i = i + 3)
{
pOut[index++] = ((pIn[i] << 4) & 0xf0) | (pIn[i + 2] & 0x0f);
pOut[index++] = (pIn[i] >> 4) & 0x0f;
//pIn[i+2] >>= 4;
pOut[index++] = ((pIn[i + 1] << 4) & 0xf0) | ((pIn[i + 2] >> 4) & 0x0f);
pOut[index++] = (pIn[i + 1] >> 4) & 0x0f;
}
printf("MipiRaw12ToP12 over\n");
}
int main(int argc, char* argv[])
{
FILE* fp = NULL;
BYTE* ptr;
BYTE* outptr = NULL;
int err = 0;
if (argc < 6) {
return -1;
}
const char* filepath = argv[1];
const char* height_str = argv[2];
const char* width_str = argv[3];
const char* bpp_str = argv[4];
const char* outfilepath = argv[5];
int width = 0;
int height = 0;
int bpp = 0;
width = atoi(width_str);
height = atoi(height_str);
bpp = atoi(bpp_str);
printf("width: %d, height: %d, bpp: %d\n", width, height, bpp);
// 输入源路径并打开raw图像文件
printf("=======raw image process===========\n");
err = fopen_s(&fp, filepath, "rb");
if (NULL == fp)
{
printf("can not open the raw image ");
return 0;
}
else
{
printf("read OK\n");
}
//Sleep(1000); /* windows 使用Sleep,参数为毫秒 */
// 分配内存并将图像读到二维数组中
fseek(fp, 0, SEEK_END);
unsigned long fsize = ftell(fp);
rewind(fp);
ptr = (BYTE*)malloc(fsize * sizeof(BYTE));
if (ptr == NULL) {
printf("ptr malloc fail\n");
return -2;
}
if (fread(ptr, 1, fsize, fp) != fsize) {
printf("read file error.\n");
return -1;
}
fclose(fp);
unsigned long outsize = width * height * 2;
outptr = (BYTE*)malloc(outsize * sizeof(BYTE));
if (outptr == NULL) {
printf("outptr malloc fail\n");
return -2;
}
if (10 == bpp) {
MipiRaw10ToP10(ptr, outptr, (width * height));
}
else if (12 == bpp) {
MipiRaw12ToP12(ptr, outptr, (width * height));
}
else if (14 == bpp) {
MipiRaw14ToP14(ptr, outptr, (width * height));
}
free(ptr);
ptr = NULL;
// 将处理后的图像数据保存
printf("Input the raw_image path for save: \n");
FILE* outfp = NULL;
err = fopen_s(&outfp, outfilepath, "wb");
if (outfp == NULL) {
printf("can not create the raw_image\n");
return 0;
}
else {
printf("fopen OK\n");
}
printf("creat file OK\n");
if (fwrite(outptr, 1, outsize, outfp) != outsize) {
printf("outptr write fail");
return -3;
}
printf("write OK\n");
fclose(outfp);
free(outptr);
outptr = NULL;
return 0;
}
注意:这里的存储方式是UnpackRaw是小端模式 + MSB优先的存储方式,MipiRaw是大端模式 + MSB优先的存储方式。可能还有别的存储方式,大家在转换的时候,先搞明白UnpackRaw和MipiRaw的存储方式再写具体代码。共勉!!!