【发布时间】:2021-07-19 20:55:09
【问题描述】:
考虑以下代码:
public static Bitmap Create3x3Bitmap(PixelFormat pixelFormat)
{
var bmp = new Bitmap(3, 3, pixelFormat);
// I know SetPixel does not perform well, this is strictly for learning purposes
bmp.SetPixel(0, 0, Color.Red);
bmp.SetPixel(1, 0, Color.Lime);
bmp.SetPixel(2, 0, Color.Blue);
bmp.SetPixel(0, 1, Color.White);
bmp.SetPixel(1, 1, Color.Gray);
bmp.SetPixel(2, 1, Color.Black);
bmp.SetPixel(0, 2, Color.Cyan);
bmp.SetPixel(1, 2, Color.Fuchsia);
bmp.SetPixel(2, 2, Color.Yellow);
return bmp;
}
上面的代码应该生成一个 3 x 3 Bitmap 实例,如果放大,应该如下所示:
我发现我可以使用Bitmap.LockBits 方法“扫描”位图的像素信息。我成功地使用了基于 24 位和 32 位的 PixelFormat 值作为 pixelFormat 参数。
但是,当使用PixelFormat.Format48bppRgb 代替时,我还没有理解如何计算像素信息:
public void Test()
{
using (var bmp = Create3x3Bitmap(PixelFormat.Format48bppRgb))
{
var lockRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var data = bmp.LockBits(lockRect, ImageLockMode.ReadWrite, bmp.PixelFormat);
var absStride = Math.Abs(data.Stride); // will be equal to 20
var size = absStride * data.Height; // will be equal to 60
byte[] scanData = new byte[size];
Marshal.Copy(data.Scan0, scanData, 0, size);
// ...
// more stuff here, irrelevant for the actual question
// ...
bmp.UnlockBits(bitmapData);
}
}
如果我使用调试器运行上面的代码并在调用Marshal.Copy 后立即中断,我可以看到scanData 字节数组包含60 个字节。我的理解是,对于三个 RGB 通道中的每一个,都需要两个字节。这意味着每个像素 6 个字节。 y 轴上的每个“行”还有两个额外的未使用字节,在本例中为 3 行。
所以如果我做对了,我应该如何解释第一行的数组内容:
现在让我感到困惑的是我应该如何解释每个通道的字节对并将其转换回原始颜色。有意义的是,对于第一个像素(红色),蓝色和绿色通道都会找到一对 0。我不太确定如何将 0 和 32 作为一对应该表示“全红”,但环顾网络,我了解到范围是 0 到 8192 而不是 0 到 65535,@ 987654323@.
果然,使用BitConverter.ToUInt16 为我得到了该对字节的值 8192。所以红色像素的结果是有意义的。
然而,它还为在灰色像素的每个通道上找到的“232, 6”对提供了 1768(上图中的索引 26 到 31)。 这就是我感到困惑的地方。由于灰色的 8 位通道在 0 到 255 的中间范围内,我预计会出现 4095 或 4096 之类的值,介于 0 到 8192 之间。????♂️
我对表示通道的字节对的理解是否正确?如果是这样,我怎么会得到这些灰色通道值?
【问题讨论】:
-
这可能会有所帮助:stackoverflow.com/a/58908209/920069