libpng返回16b / channel truecolour ImageMagick图像的无效数据

时间:2016-01-18 16:48:23

标签: imagemagick libpng

我有一个真彩色图像,每个通道16位(由ImageMagick创建),我想读入单独的R,G,B平面。问题是得到的16位像素值只是复制了结果中的低字节和高字节。例如,如果红色组件的近似值为0x42,则我的libpng代码实际上返回值0x4242。

我的第一个问题是我不太相信输入实际上有16位像素。这是identify -verbose返回的内容:

   Type: TrueColor    
   Endianess: Undefined    
   Colorspace: RGB
   Depth: 16/8-bit    
   Channel depth:
      red: 8-bit
      green: 8-bit
      blue: 8-bit    
   Channel statistics:
      Red:
       min: 0 (0)
       max: 65535 (1)
   Properties:
      PNG:IHDR.bit_depth       : 16
      PNG:IHDR.color_type      : 2

这个图像实际上是否有我可以提取的16位数据?如果是这样,怎么样?我的libpng读取代码基本上是这样做的(确认png_get_color_type返回2后,png_get_bit_depth返回16):

   png_uint_32 rowbytes = png_get_rowbytes(png, info);
   image        = (png_byte *) xmalloc(height * rowbytes);
   row_pointers = (png_bytep*) xmalloc(sizeof(png_bytep) * height);

   for(int i = 0; i < (int)height; i++)
      row_pointers[i] = image + (i*rowbytes);

   png_read_image(png, row_pointers);

我的代码将image拆分为RGB平面,这样做:

   uint16_t *src = (uint16_t*) image;   // libpng composite image
   uint16_t *rplane, *gplane, *bplane;  // separate planar channels
   ...
   for(size_t i=0; i<nrows; i++) {
      for(size_t j=0; j<ncols; j++) {
         *rplane++ = *src++;
         *gplane++ = *src++;
         *bplane++ = *src++;
      }
   }

所以这假设libpng返回的48位像素数据是16b R,然后是16b B,然后是16b G.

如果我将图像读入Matlab,它会报告由于ImageMagick的限制,它只能读取8-b像素。如果Matlab报告像素(x,y)有红色例如,0x42的组件,上面的libpng代码报告它的值为0x4242。但是,Matlab和上面的libpng代码都同意所有像素的RGB值,之外,Matlab将它们全部报告为单个8位组件,libpng代码在每个16位中复制此值两次成分

有什么想法吗?感谢。

修改

非详细identify输出:

> identify in.png
in.png PNG 2776x2776 2776x2776+0+0 16-bit DirectClass 14.35MB 0.000u 0:00.000

2 个答案:

答案 0 :(得分:2)

“识别”报告中的“深度:16/8位”行表示图像以16位样本存储,但所有像素都可以使用8位表示而不丢失。也就是说,每个像素的每个分量都有一个值,其高字节等于其低字节(即,具有可被257整除的值)。

例如,对于此PPM图像

P3 2 2 65535
    0     0     0
32896 32896 32896
32896 32896 32896
65535 65535 65535

样本均可被257和25整除 识别-verbose file.ppm报告

Depth: 16/8-bit
  Channel depth:
    gray: 8-bit

但如果您将最后一行更改为“65535 65535 65534”, 然后识别-verbose file.ppm报告

Depth: 16-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 16-bit

要了解图像实际存储在PNG文件中的方式,您必须查看“识别”所示的PNG:IHDR属性。或者您可以使用“pngcheck”获取有关PNG文件内容的真实报告。

有一个关于样本缩放的解释 PNG specification。当从8位样本缩放到16位样本时,ImageMagick通过简单地乘以或除以257.0来实现这一点,反之亦然。请参阅ImageMagick源中的“ScaleQuantumToShort()”和“ScaleShortToQuantum()”内联函数。

答案 1 :(得分:1)

如果我制作的图像1000x1000充满了难以压缩的随机数据,那么它的亮度为5.7MB(正如您所期望的那样,100位像素的16位红色,16位绿色和16位蓝色)并根据identify显示为16位:

convert -size 1000x1000! xc:gray +noise random image.png

ls -lhrt
-rw-r--r--      1 mark  staff   5.7M 18 Jan 16:59 image.png

identify image.png
image.png PNG 1000x1000 1000x1000+0+0 16-bit sRGB 6.011MB 0.000u 0:00.000

如果我现在使用8位像素做同样的事情:

convert -size 1000x1000! xc:gray +noise random -depth 8 image.png

它在identify中显示为8位,占用了一半的空间:

identify image.png
image.png PNG 1000x1000 1000x1000+0+0 8-bit sRGB 3.006MB 0.000u 0:00.000

ls -lhrt
-rw-r--r--      1 mark  staff   2.9M 18 Jan 17:01 image.png

所以我推断identify说实话,我很确定你的图像实际上不是16位。你是怎么创造它的?

根据Glenn的回答,我想一个解决方法可能是将图像的左上角或右下角像素设置为所有三个通道中的素数,如65,521,这应该可以有效地防止任何图像可存储在一个字节中!只需在后续处理中忽略该像素,或者如果您迫切需要其值,请添加一行额外的虚拟数据。