在PNG中将16位灰度映射到8位

问题描述 投票:2回答:1

我正在尝试用C#中的每个通道16位(bpc)解码一个PNG,用于灰度图像。我相信我正在解码正确的原始值但是当我转换为8bpc以返回值时,我不会计算与System.Drawing,Gimp或SixLabors.ImageSharp相同的值。

给定单个灰度像素的以下字节值:

byte b0 = data[index];
byte b1 = data[index + 1];

我尝试了以下映射:

byte result = b0;
byte result = (byte)(255 * (((b0 << 8) + b1)/ushort.MaxValue));
byte result = (byte)(((b0 << 8) + b1)/256.0);

但是,这些方法似乎都与其他预测的以下值的软件的值相匹配:

b0   b1   expected
55   186  55
67   135  67
35   241  36

我确定我误解了将标准化归回到8 bpc值的正确方法。

有问题的图片是这样的:

A 16 by 16 pixel Grayscale image with 16 bpc

c# png
1个回答
1
投票

这是转换位深度的官方方法:

https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling

output = floor((input * MAXOUTSAMPLE / MAXINSAMPLE) + 0.5)

where

MAXINSAMPLE = (2^sampledepth)-1
MAXOUTSAMPLE = (2^desired_sampledepth)-1

所以如果我采取你的最后一个例子:

35 << 8 | 241 == 8960 | 241 == 9201
9201 * 255 / 65535 == 2346255 / 65535 == 35
floor(35 + 0.5) == 35

为什么不36

There might gamma being involved

结论:

首先检查您的内部实施是否正确遵循规范,然后相应地进行调整。

https://www.w3.org/TR/2003/REC-PNG-20031110/

© www.soinside.com 2019 - 2024. All rights reserved.