将RGB 444转换为可显示的图像

时间:2014-02-26 09:50:13

标签: c++ c image qt rgb

我在嵌入式设备中使用了一种奇怪的图像格式,像往常一样,文档没有帮助......

以下是两行doc:

图片是:

  

全彩色位图(每像素4 + 4 + 4位),3个字节   每两个像素(从左到右的像素序列)。

因此,为了能够获得一个字节序列的图像,我编写了以下代码:

// size_x and size_y are known at this point
QImage img(size_x, size_y, QImage::Format_RGB444); 
int xctr = 0;
int yctr = 0;
for(int c1 = 0; c1 < bsize; ) // bsize is the size of image bytes
{
    static const int M = 1; // a multiplier to make the image brighter
    uint8_t b1 = *(p_pos + c1++); // p_pos points to the first image byte
    uint8_t b2 = *(p_pos + c1++);
    uint8_t b3 = *(p_pos + c1++);

    uint8_t pix1_r =( (b1 & 0xF0) >> 4 ) * M;
    uint8_t pix1_g =( (b1 & 0xF) ) * M;
    uint8_t pix1_b =( (b2 & 0xF0) >> 4 ) * M;

    uint8_t pix2_r =( (b2 & 0xF) ) * M;
    uint8_t pix2_g =( (b3 & 0xF0) >> 4 ) * M;
    uint8_t pix2_b =( (b3 & 0xF) ) * M;

    // old code
    //unsigned int pix1 = pix1_r << 8 | pix1_g << 4 | pix1_b;
    //unsigned int pix2 = pix2_r << 8 | pix2_g << 4 | pix2_b;

    // new code
    unsigned int pix1 = ((unsigned int)pix1_r) << 8 | pix1_g << 4 | pix1_b;
    unsigned int pix2 = ((unsigned int)pix2_r) << 8 | pix2_g << 4 | pix2_b;

    // set the first pixel
    img.setPixel(xctr, yctr, pix1);
    xctr ++;
    if(xctr == size_x) {
        xctr = 0;
        yctr ++;
    }

    // set the second pixel
    img.setPixel(xctr, yctr, pix2);
    xctr ++;
    if(xctr == size_x) {
        xctr = 0;
        yctr ++;
    }
}

这是我得到的图像:

My image

这是一张我应该得到的图像(非常类似)(只有蓝色/洋红色部分,请不要考虑黑色背景和雪:) :):

What I expect

对于勇敢的图像数据:http://pastebin.com/m4y8qamB,请随意使用此Python creating an array from hex bytes将原始数据转换为“实际”十六进制字节。

问题是:现在,忽略嵌入设备本身的图像调色板,我错误地做了什么,以至于我没有获得与预期相似的图像?我该怎么做才能得到类似的图像?

编辑在添加解码值(和打印字符)的一些打印输出后,我得到类似的内容:

PPPPPPPPPPPPPPPPPPPAPPPPPPPPPPPP
PPPPPPPAPPPPPPPPPPPPPPPPPPPAPPPP
PPPPPPPPPPPPPPPAPPPPPPPPPPPPPPPP
PPPAPPPPPPPPPPPPPPPPPPPAPPPPPPPP
PPPPPPPPPPPAPPPPPPPPPPPPPPPPPPPA
PPPPPPPPPPPPPPPPPPPAPPPPPPPPPPPP
PPPPPPPAPPPPPPPPPPPPPPPPPPPAPPPP
PGPPPPPPPPPPPPPAPPPPPCANMMMMMMMM
MMMMAMMMMOPCALDDDDDDDDDDDADDDMPC
ANODDDDDDDDDDDDADDKPANPCAGMMMMMM
MMMMMMAMMNPCANPCANPCANPCANPCANPC
ANPCANPPPAPPANPCANPCANPCANPCANPC
ANPCANPCADDADDPCANPCANPCANPCANPC
ANPCANPCANPCMMAMMMMMMMMMMMMMMMMM
MMAMMMMMMMMMMMMMMMMMMMAMMMMMMMMM
MMMMMMMMMMAMMMMMMMMMMMMMMMMMMMAM
MMMMMMMMMMMMMMMMMMAMMMMMMMMMMMMM
MMMMMMAMMMMMMMMMMMMMMMMMMMAMMMMM
MMMMMMMMMMMMMMAMMMMMMMMMMMMMMMMM
MMAMMMMMMMMMMMMMMMMMMMAMMMMMMMMM

2 个答案:

答案 0 :(得分:2)

我使用

将pastebin数据转换为二进制文件
perl -pe 's/([0-9a-f]{2})\s+/chr(hex($1))/ige' > tempfile

当我查看该文件的十六进制转储时,这似乎是正确的。

然后我写了一个解码该文件的程序:

    #include <stdio.h>

    typedef unsigned char uint8_t;
    #define M 1

    int main(void) {
            FILE *fp;

            int sizex, sizey;
            int xctr, yctr;
            int i=0;

            if ((fp=fopen("tempfile", "rb"))==NULL) {
                    perror("tempfile"); exit(1);
            }
            sizey=getc(fp);
            sizex=getc(fp);
            int bsize=getc(fp)*256;
            bsize+=getc(fp);

            xctr=yctr=0;
            for (i=0; i<bsize/3; i++) {
                    uint8_t b1=getc(fp);
                    uint8_t b2=getc(fp);
                    uint8_t b3=getc(fp);

                    uint8_t pix1_r =( (b1 & 0xF0) >> 4 ) * M;
                    uint8_t pix1_g =( (b1 & 0xF) ) * M;
                    uint8_t pix1_b =( (b2 & 0xF0) >> 4 ) * M;

                    uint8_t pix2_r =( (b2 & 0xF) ) * M;
                    uint8_t pix2_g =( (b3 & 0xF0) >> 4 ) * M;
                    uint8_t pix2_b =( (b3 & 0xF) ) * M;

                    unsigned int pix1 = ((unsigned int)pix1_r) << 8 | pix1_g << 4 | pix1_b;
                    unsigned int pix2 = ((unsigned int)pix2_r) << 8 | pix2_g << 4 | pix2_b;

                    printf("%3x ", pix1);
                    xctr++;
                    if (xctr==sizex) {
                            putchar('\n');
                            xctr=0;
                    }
                    printf("%3x ", pix2);
                    xctr++;
                    if (xctr==sizex) {
                            putchar('\n');
                            xctr=0;
                    }
            }
    }

或多或少地做你的工作,并有输出:

    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393 393
    393 393 393 393 393 393 393 999 ddd eee bcc 393 393 999 fd0 2fd 02f d02 fd0 2f9 993 933 933 933 939 99f fd0 2fd
    02f d02 fd0 2fd 02f ccc 666 ffd 02f d02 fd0 2fd 02f d02 fd0 2fd 029 993 933 933 93d ddf fd0 2fd 02f d02 fd0 2fd
    02f d02 fd0 2ee eff d02 fd0 2fd 02f d02 fd0 2fd 02f d02 ddd 393 393 393 fd0 2fd 02f d02 bbb 393 bcc ffd 02f d02
    fd0 1ee 393 393 bbb ffd 02f d02 f39 339 339 3fd 02f d02 fd0 239 339 339 3ee efd 02f 999 393 393 393 ffd 02f d02
    f39 339 339 3fd 02f d02 fd0 2aa a39 399 9ff d02 fd0 2fd 01e e39 339 399 9ff d02 fd0 2f3 933 933 93d ddf fd0 2fd
    02f d02 fd0 2fd 02f d02 fd0 2fd 02f d02 fd0 2fd 02f d01 eef d02 fd0 2fd 02d dd3 933 933 938 88f fd0 2fd 02f d02
    fd0 2fd 02f aaa 999 ffd 02f d02 fd0 2fd 02f d02 fd0 2fd 029 993 933 933 933 938 88c ccc cc9 993 933 93a aaf d02
    fd0 2fd 02f d02 f99 939 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339
    339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339
    339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339
    339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339 339

似乎解码过程没问题,但输出仍然看起来不像图像。

再次查看原始的pastebin数据,我几乎可以肯定该数据存在一些错误。在开始时,序列'39 33 93'重复几次,很好地转换为393 393.但后来,你有'FD 02 FD 02 FD 02 FD 02'。这将转换为'FD0 2FD 02F D02 FD0 2 ..',我无法想象这是正确的。是否有可能缺少某些字节(如\ 0字节未被传输),而结尾339实际上是属于下一个图像的数据?

答案 1 :(得分:1)

我不能让问题休息;)我注意到我的文件有2F7(十六进制)字节,但标题是02A0,所以必须有文件中的内容但输出时必须忽略。然后,我知道如果你从输入中省略所有'F'半字节会发生什么(并且从输出中省略393)会发生什么,但结果看起来不太好,特别是39 33 93有时会被移位解码为933 933 933。

接下来,我省略了所有F和E半字节,结果是:


    start of image









                999 ddd bcc         999 d02 d02 d02 d02 999
            999 d02 d02 d02 d02 d02 ccc 666 d02 d02 d02 d02 d02 d02
    d02 999             ddd d02 d02 d02 d02 d02 d02 d02 d02 d02 d02
    d02 d02 d02 d02 ddd             d02 d02 d02 bbb     bcc d02 d02
    d01         bbb d02 d02             d02 d02 d02             d02
    999             d02 d02             d02 d02 d02 aaa     999 d02
    d02 d01         999 d02 d02             ddd d02 d02 d02 d02 d02
    d02 d02 d02 d02 d02 d02 d01 d02 d02 d02 ddd             888 d02
    d02 d02 d02 d02 aaa 999 d02 d02 d02 d02 d02 d02 d02 999
            888 ccc ccc 999         aaa d02 d02 d02 d02 999









    I'm now at 02df
    end of image

看起来并不完全正确,但比我们迄今为止所做的一切要好得多。我假设更多的东西必须省略,因为代码读取直到0x2df,而不是0x2f7,但这可能有助于你找到你还要做的其他事情。这是我的代码;请注意我首先读取sizey,然后读取sizex,因为这似乎可以产生更好的图像:

    #include <stdio.h>

    typedef unsigned char uint8_t;
    #define M 1

    int sizex, sizey;
    int xctr, yctr;

    int main(void) {
            FILE *fp;

            int i=0, c;
            int flag;

            if ((fp=fopen("tempfile", "rb"))==NULL) {
                    perror("tempfile"); exit(1);
            }
            sizey=getc(fp);
            sizex=getc(fp);
            int bsize=getc(fp)*256;
            bsize+=getc(fp);

            xctr=yctr=0;
            for (i=0; i<bsize*2;) {
                    c=getc(fp);
                    if ((c&0xf0) != 0xf0 && (c&0xf0) != 0xe0) {
                            push ((c>>4)&0x0f);
                            i++;
                    }
                    if ((c&0x0f) != 0x0f && (c&0x0f) != 0x0e) {
                            push (c&0x0f);
                            i++;
                    }

            }
            printf("I'm now at %04x\n", ftell(fp));
    }


    int push(int c) {
            static int pos=0;
            static uint8_t red, green, blue;

            if      (pos==0) { pos=1; red=c; }
            else if (pos==1) { pos=2; green=c; }
            else if (pos==2) { pos=0; blue=c; }

            if (pos==0) {
                    if (red==3 && green==9 && blue==3)
                            printf("    ");
                    else
                            printf("%01x%01x%01x ", red, green, blue);
                    xctr++;
                    if (xctr==sizex) {
                            putchar('\n');
                            xctr=0;
                    }
            }
    }