这是一个快速且简单的实现:
void Main()
{
var a = (Bitmap)Image.FromFile("image1.png");
var b = (Bitmap)Image.FromFile("image2.png");
var diff = PixelDiff(a, b);
}
unsafe Bitmap PixelDiff(Bitmap a, Bitmap b)
{
Bitmap output = new Bitmap(a.Width, a.Height, PixelFormat.Format32bppArgb);
Rectangle rect = new Rectangle(Point.Empty, a.Size);
using (var aData = a.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
using (var bData = b.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
using (var outputData = output.LockBitsDisposable(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb))
{
byte* aPtr = (byte*)aData.Scan0;
byte* bPtr = (byte*)bData.Scan0;
byte* outputPtr = (byte*)outputData.Scan0;
int len = aData.Stride * aData.Height;
for (int i = 0; i < len; i++)
{
if ((i + 1) % 4 == 0)
*outputPtr = (byte)((*aPtr + *bPtr) / 2);
else
*outputPtr = (byte)~(*aPtr ^ *bPtr);
outputPtr++;
aPtr++;
bPtr++;
}
}
return output;
}
static class Extensions
{
public static DisposableImageData LockBitsDisposable(this Bitmap bitmap, Rectangle rect, ImageLockMode flags, PixelFormat format)
{
return new DisposableImageData(bitmap, rect, flags, format);
}
public class DisposableImageData : IDisposable
{
private readonly Bitmap _bitmap;
private readonly BitmapData _data;
internal DisposableImageData(Bitmap bitmap, Rectangle rect, ImageLockMode flags, PixelFormat format)
{
bitmap.CheckArgumentNull("bitmap");
_bitmap = bitmap;
_data = bitmap.LockBits(rect, flags, format);
}
public void Dispose()
{
_bitmap.UnlockBits(_data);
}
public IntPtr Scan0
{
get { return _data.Scan0; }
}
public int Stride
{
get { return _data.Stride;}
}
public int Width
{
get { return _data.Width;}
}
public int Height
{
get { return _data.Height;}
}
public PixelFormat PixelFormat
{
get { return _data.PixelFormat;}
}
public int Reserved
{
get { return _data.Reserved;}
}
}
}
注:
- 这个实现假定两个图像具有相同的大小,但实际情况可能不是这样的... 当然,考虑不同的大小是可能的,只是会更加困难。
LockBitsDisposable
方法仅仅是一种便捷方式,如果你喜欢可以使用标准的 LockBits
方法(但别忘了在完成后解锁位)。
*outputPtr = (byte)~(*aPtr ^ *bPtr);
或Attempt to read or write Protected Memory This is often an indicating that other memory is corrupt
。你能帮我看看吗? - user3548681len
也应该是负数,所以它甚至不应该进入循环,因此您不应遇到此错误...无论如何,请尝试使用Math.Abs(aData.Stride)
而不是aData.Stride
。 - Thomas Levesque*outputPtr = *outputPtr = (byte)*bPtr;
它抛出了一个错误Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
... 我正在这里苦思冥想,哈哈。 - user3548681