MIPIRaw转UnpackRaw

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的存储方式再写具体代码。共勉!!!

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值