c# - 48 位位图中灰色像素的意外 RGB channel 值

标签 c# .net .net-core gdi+

跟进 this question .

我已经设法使用 Bitmap.LockBits 从位图实例中提取像素信息。 PixelFormatFormat48bppRbg,根据我的理解和 Peter's answer关于上述问题,应该使用两个字节存储每个像素的RGB颜色 channel 。字节的组合值应等于 0 到 8192 之间的数字,表示 RBG channel 强度值。该值是通过将两个字节传递给 BitConverter.ToUInt16 方法获得的。

因此,在为以下 3 x 3 位图提取像素信息时(为清楚起见,此处已放大):

bitmap

我的第一行像素 channel 是这样的:

<表类="s-表"> <头> 像素颜色 红色强度 绿色强度 蓝色强度 <正文> 红色 8192 0 0 绿色 0 8192 0 蓝色 0 0 8192

到目前为止一切顺利。

然而,在第二行,它是这样的:

<表类="s-表"> <头> 像素颜色 红色强度 绿色强度 蓝色强度 <正文> 白色 8192 8192 8192 灰色 (!) 1768 (!) 1768 (!) 1768 (!) 黑色 0 0 0

白色和黑色像素 channel 值对我来说很有意义。

然而,灰色却没有。

如果您在上面的灰色像素上使用任何颜色选择器,您应该会得到完美的中灰色。在 24 位颜色中,它应该等效于 (R: 128, G: 128, B: 128),或十六进制形式的 #808080。

那么为什么在 Format48bppRpg 像素格式中, channel 强度远低于预期的中间 4096 值?这个基于 GDI+ 的 0-8192 范围不应该像它的 8 位对应物一样工作,0 是最低强度而 8192 是最高强度吗?我在这里缺少什么?

作为引用,这里是 Visual Studio 调试器的屏幕截图,显示了原始字节索引和值,以及关于步幅、 channel 位置及其提取的强度值的附加注释,直到灰色像素:

screen capture

最佳答案

您陈述错误假设的部分是 #808080 是“完美的中灰色”。它不是,至少如果你从某种角度来看它不是(更多关于它 here )。

许多颜色标准,包括 sRGB,使用 gamma compression使较暗的颜色在通常用于存储 RGB 颜色的 256 个值的范围内间隔更大。这大致意味着在编码该值之前取相对分量值的平方根(或 2.2 根)。原因是人眼(与其他感官一样)以对数方式感知亮度,因此,即使亮度在算术上很小的变化也很重要,如果这实际上意味着亮度加倍的话。

128 的字节值实际上大约是全亮度的 21.95 % (128/255 ^ 2.2),这是您在 16 位组件的情况下看到的。可能值的空间更大,因此 GDI(或格式)不再需要以特殊方式存储它们。

如果您需要算法,取值的 2.2 根通常效果很好,但正确的公式有点不同,请参阅 here .根函数通常具有接近零的无限斜率,因此特定公式试图通过使该部分线性化来解决该问题。可以很容易地从中导出一段代码:

static byte TransformComponent(ushort linear)
{
    const double a = 0.055;
    var c = linear / 8192.0;
    c = c <= 0.0031308 ? 12.92 * c : (1 + a) * Math.Pow(c, 1/2.4) - a;
    return (byte)Math.Round(c * Byte.MaxValue);
}

这为 1768 的值提供了 128。

关于c# - 48 位位图中灰色像素的意外 RGB channel 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68470168/

相关文章:

c# - 在 Visual Studio 中输出控制台应用程序而不是控制台

c# - Path.Combine 是否曾在 .net 中进行过网络调用?

c# - C# 中未引发异常。只是踢出了常规。这是一个错误吗?

c# - 在 CodeObjectCreateExpression 中分配对象的属性值

javascript - 从命名索引 JS 获取数组值

c# - 从 Toast 通知激活时应用程序在启动时崩溃

c# - 从 C# 代码隐藏动态添加到 DIV 标签的链接

c# - 在 C#/.NET 环境中对输入进行全局验证?

c# - 如何在c#中使用kubernetes-client创建k8s部署?

.net-core - 查找生成器 'identity' ...给定的程序集名称或代码库无效