我有一个真彩色图像,每个通道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
答案 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,这应该可以有效地防止任何图像可存储在一个字节中!只需在后续处理中忽略该像素,或者如果您迫切需要其值,请添加一行额外的虚拟数据。