从单通道转换12位小端原始二进制数据

时间:2015-09-24 13:02:07

标签: imagemagick imagemagick-convert

我有一个原始二进制图像文件,其中每个像素由12位数据(灰度)组成。例如,原始文件中的前四个像素:

0x0  0xC0
0x1  0x05
0x2  0x5C
0x3  0xC0
0x4  0x05
0x5  0x5C

这对应于4个像素值,值为0x5C0(小端)。

不幸的是,使用以下命令:

convert -size 384x184 -depth 12 gray:frame_0.raw out.tiff

错误地解释像素值(大端),从而产生像素值0xC00 0x55C 0xC00 0x55C

我尝试了-endian LSB-endian MSB选项,但遗憾的是它们只更改了输出字节顺序,而不是输入字节顺序。

如何转换为将原始图像打开为12位小端数据?

2 个答案:

答案 0 :(得分:1)

我对此进行了快速尝试,但我没有测试数据,但它应该非常接近并且很容易检测到您的图像错误:

// pad12to16.c
// Mark Setchell
// Pad 12-bit data to 16-bit
//
// Compile with:
// gcc pad12to16.c -o pad12to16
//
// Run with:
// ./pad12to16 < 12-bit.dat > 16-bit.dat

#include <stdio.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/types.h>

#define BYTESPERREAD    6
#define PIXPERWRITE     4

int main(){
    unsigned char  buf[BYTESPERREAD];
    unsigned short pixel[PIXPERWRITE];

    // Read 6 bytes at a time and decode to 4 off 16-bit pixels
    while(read(0,buf,BYTESPERREAD)==BYTESPERREAD){
       pixel[0] = buf[0] | ((buf[1] & 0xf) << 8);
       pixel[1] = (buf[2] << 4) | ((buf[1] & 0xf0) >> 4);
       pixel[2] = buf[3] | ((buf[2] & 0xf) << 8);
       pixel[3] = (buf[5] << 4) | ((buf[4] & 0xf0) >> 4);
       write(1,pixel,PIXPERWRITE*2);
    }
    return 0;
}

所以你会跑这个(我想):

./pad12to16 < 12-bit.dat | convert -size 384x184 -depth 16 gray:- result.tif 

答案 1 :(得分:1)

Mark的回答是正确的,因为您需要使用一些外部工具来整理数据流。通常在使用12位深度时会有某种填充。在提供的示例blob中,我们看到每对像素共享一个公共字节。拆分共享字节,并将什么到哪里转移相当容易。这个答案与马克的答案相称,并认为ImageMagick's C-API也可以使用。

// my12bit_convert.c
#include <stdio.h>
#include <stdlib.h>
#include <magick/MagickCore.h>
#include <wand/MagickWand.h>

static ExceptionType serverty;

#define LEADING_HALF(x) ((x >> 4) & 0xF)
#define FOLLOWING_HALF(x) (x & 0xF)
#define TO_DOUBLE(x) ((double)x / (double)0xFFF);
#define IS_OK(x,y) if(x == MagickFalse) { fprintf(stderr, "%s\n", MagickGetException(y, &serverty)); }


int main(int argc, const char * argv[]) {
    // Prototype vars
    int
        i,
        tmp_pixels[2];
    double * pixel_buffer;
    size_t
        w = 0,
        h =0,
        total = 0,
        iterator = 0;
    ssize_t
        x = 0,
        y = 0;
    const char
        * path = NULL,
        * output = NULL;
    unsigned char read_pixel_chunk[3];
    FILE * fh;

    MagickWand * wand;
    PixelWand * pwand;
    MagickBooleanType ok;

    // Iterate over arguments and collect size, input, & output.
    for ( i = 1; i < argc; i++ ) {
        if (argv[i][0] == '-') {
            if (LocaleCompare("size", &argv[i][1]) == 0) {
                i++;
                if (i == argc) {
                    fprintf(stderr, "Missing `WxH' argument for `-size'.");
                    return EXIT_FAILURE;
                }
                GetGeometry(argv[i], &x, &y, &w, &h);
            }
        } else if (path == NULL){
            path = argv[i];
        } else {
            output = argv[i];
        }
    }

    // Validate to some degree
    if ( path == NULL ) {
        fprintf(stderr, "Missing input path\n");
        return EXIT_FAILURE;
    }
    if ( output == NULL ) {
        fprintf(stderr, "Missing output path\n");
        return EXIT_FAILURE;
    }
    total = w * h;
    if (total == 0) {
        fprintf(stderr, "Unable to determine size of %s. (use `-size WxH')\n", path);
        return EXIT_FAILURE;
    }

    // Allocated memory and start the party!
    pixel_buffer = malloc(sizeof(double) * total);
    MagickWandGenesis();

    // Read input file, and sort 12-bit pixels.
    fh = fopen(path, "rb");
    if (fh == NULL) {
        fprintf(stderr, "Unable to read `%s'\n", path);
        return 1;
    }
    while(!feof(fh))  {
        total = fread(read_pixel_chunk, 3, 1, fh);
        if (total) {
            // 0xC0 0x05
            //  ^------'   ==> 0x05C0
            tmp_pixels[0] = FOLLOWING_HALF(read_pixel_chunk[1]) << 8 | read_pixel_chunk[0];
            // 0x05 0x5C
            //   '------^  ==> 0x05C0
            tmp_pixels[1] = read_pixel_chunk[2] << 4 | LEADING_HALF(read_pixel_chunk[1]);
            // 0x5C0 / 0xFFF ==> 0.359463
            pixel_buffer[iterator++] = TO_DOUBLE(tmp_pixels[0]);
            pixel_buffer[iterator++] = TO_DOUBLE(tmp_pixels[1]);
        }
    }
    fclose(fh);

    // Create image
    wand = NewMagickWand();
    pwand = NewPixelWand();
    ok = PixelSetColor(pwand, "white");
    IS_OK(ok, wand);
    // Create new Image
    ok = MagickNewImage(wand, w, h, pwand);
    IS_OK(ok, wand);
    // Import pixels as gray, or intensity, values.
    ok = MagickImportImagePixels(wand, x, y, w, h, "I", DoublePixel, pixel_buffer);
    IS_OK(ok, wand);
    // Save ouput
    ok = MagickWriteImage(wand, output);
    IS_OK(ok, wand);

    // Clean house
    DestroyPixelWand(pwand);
    DestroyMagickWand(wand);
    MagickWandTerminus();
    if (pixel_buffer) {
        free(pixel_buffer);
    }
    return 0;
}

可以用

编译
LLVM_CFLAGS=`MagickWand-config --cflags`
LLVM_LDFLAGS=`MagickWand-config --ldflags`
clang $LLVM_CFLAGS $LLVM_LDFLAGS -o my12bit_convert my12bit_convert.c

使用

./my12bit_convert -size 384x184 frame_0.raw out.tiff