这段代码与我使用的类似。绝对,在这种情况下,不安全的代码是唯一的出路。没有必要在内存周围编组一个充满像素的位图,您必须这样做两次才能进行比较!
但是,比较像素应该被视为比较两个数字。由于一个像素对于颜色的红色、绿色和蓝色分量中的每一个都是 3 个字节,当然还有 Alpha(通常被忽略),您可能希望将值作为 UInt32 进行比较。这将有利于将一个数字(一个像素)与另一个进行比较,如果它们相同,那么您继续前进。
为此,您不需要一个字节*,而是一个 UInt32*。其次,上面的代码没有考虑我可以看到的步幅,这是图像的每条水平线实际上使用的字节数可能与像素本身的总和不同。由于您可能正在处理 24 位 (rgb) 和 alpha (a),这意味着像素应该已经对齐,因此上面的代码应该可以工作。然而,不能保证它会 100% 的发生。
听起来我真的很挑剔,但我猜性能对你来说很重要——而且来自游戏背景,对我也很重要。
(摘自上述第 1 部分的链接,感谢 Karl-Johan Sjögren)
BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
当您点击这条线时,您真的需要小心 - 您锁定的 PixelFormat 应该与您的源图像的 PixelFormat 之一匹配。否则事情可能不会像你期望的那样表现。
从 LockBits 中,您将获得需要深入研究的 BitmapData。
byte* scan0 = (byte*)bData.Scan0.ToPointer();
这就是我所指的行 - 我将其设为 UInt32*,因此您不是每条指令读取一个字节,而是一次性读取 4 个字节,作为 UInt32。
我将把这个内存作为一个数组来访问——我通过识别步幅等于一个 Y 像素来计算一维数组的偏移量,因此将步幅乘以 Y。但是,你会陷入同样的境地在这一点上我有很多次陷阱!
int stride = bData.Stride / 4; // the width is expressed in bytes, yet we need it as UInt32's. As there's 4 bytes per UInt32, this makes sense of the divide by 4.
因此可以通过这种方式读取像素:
int x = 123;
int y = 321;
UInt32 pixelColour = scan0[(y * stride) + x];
最后,完成后不要忘记解锁位图。一个容易忘记的。此外,如果您希望将更改的像素保存到另一个位图,您需要以相同的方式写入像素。我认为我的示例使用指针作为数组来读取像素应该很明显如何执行相同的操作来写入像素。
另一种想法——我希望你不要试图比较 Jpeg 或其他有损压缩图像——因为这些变化可能非常不可预测,而且与你想象的不完全一样。相反,您需要使用无损图像格式,例如 BMP 和 PNG。
希望这可以帮助某人。