比较两个位图问题

时间:2013-12-06 15:57:48

标签: c# .net arrays bitmap

我有一个具有Bitmap属性的Class。我已经为对象实现了Equals覆盖,我遇到了Bitmap比较的问题。这就是我所拥有的:

[Serializable]
public class Contact
{
    public string Name { get; set; }
    public Bitmap Photo { get; set; }

    public override bool Equals(object obj)
    {
        if (obj == null) { return false; }
        if (obj.GetType() != typeof(Contact)) { return false; }

        Contact compareContact = obj as Contact;

        if (compareContact.FirstName != this.FirstName) { return false; }

        if (compareContact.Photo != null && this.Photo != null)
        {
            if (!compareContact.Photo.IsEqual(this.Photo)) { return false; }
        }
        else
        {
            if (!(compareContact.Photo == null && this.Photo == null)) { return false; }
        }

        return true;
    }
}

public static class BitmapExtensions
{
    public static bool IsEqual(this Bitmap image1, Bitmap image2)
    {
        if (image1 == null || image2 == null)
        {
            return false;
        }

        byte[] image1Bytes =  image1.ToByteArray();
        byte[] image2Bytes =  image2.ToByteArray();

        bool sequenceEqual = image1Bytes.SequenceEqual(image2Bytes);

        return sequenceEqual;
    }

    public static byte[] ToByteArray(this Bitmap image)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            image.Save(ms, ImageFormat.Bmp);
            return ms.ToArray();
        }
    }
}

我的测试:

[TestClass()]
public class vCardTest
{
    private Contact TestContact()
    {
        Contact contact = new Contact();
        contact.Name = "Joe";
        contact.Photo = new System.Drawing.Bitmap(1, 1);
    }

    [TestMethod]
    public void EqualsTest()
    {
        Contact matchedContact  = Common.Copy<Contact >(TestContact);

        Assert.AreEqual<vCard>(vcf, matchedVCard);
    }

我的复制方法:

    public static T Copy<T>(T objectToCopy) where T : class
    {
        byte[] serializedObject = objectToCopy.Serialize();
        T copy = serializedObject.Deserialize(typeof(T)) as T;

        return copy;
    }

我的等于函数返回false。当我查看原始位图和副本的字节数组时,我注意到数组中的58个字节中的两个字节是一个。两个字节数组具有相同的长度。

我正在试图弄清楚序列化和反序列化位图以制作副本是否会导致问题或其他原因。

更新

Common.Copy方法似乎没有引起问题,这个带字节数组的代码成功运行:

    [TestMethod()]
    public void ByteArrayCommonCopyTest()
    {
        byte[] byteArray1 = new byte[] { 0, 1, 1, 0, 123, 45, 56, 0 };
        byte[] byteArray2 = Common.Copy<byte[]>(byteArray1);
        bool expected = true;
        bool actual;

        actual = byteArray1.SequenceEqual(byteArray2);

        Assert.AreEqual(expected, actual);
    }

有趣的是,如果我将Photo更新为具有相同大小的新位图,则可以正常工作:

    [TestMethod]
    public void EqualsTest()
    {
        Contact matchedContact  = Common.Copy<Contact>(TestContact);
        matchedContact.Photo = new System.Drawing.Bitmap(1, 1)

        Assert.AreEqual<vCard>(vcf, matchedVCard);
    }

1 个答案:

答案 0 :(得分:0)

这是您正在做的事情(我不会这样做) - 您将图像流式传输为bmp格式的流,然后进行比较。这里的问题是在内存和bmp文件中,你的数据逐行填充到4个字节。可能差异在填充中,在绘图中会被忽略。

相反,你应该写一个合适的比较器。两个位图是if:

  • 他们是同一个对象

  • 宽度,高度,分辨率和像素格式匹配
  • 调色板匹配
  • 图像数据相同

尺寸易于检查,应首先进行,因为这些测试很便宜。

要比较图片数据,您可以对图片中的每个像素进行GetPixel()调用,也可以尝试使用LockBits()直接访问图片数据以获取BitmapData对象并仅提取行中的重要字节以进行比较。后者是可行的,但代码需要能够正确回答问题,“给定一个位图,每行有多少重要字节?”适用于任何特定的PixelFormat。即便如此,您还是要将每一行复制到行缓冲区中,然后在其上运行字节数组比较器。也许一旦你开始运行,你可能会对P/Invoke to memcmp的性能感到满意,或者不使用数组,而是从第一条扫描线IntPtr直接指针运算,然后执行memcmp:

[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(IntPtr b1, IntPtr b2, long count);

bool ScanlinesAreTheSame(IntPtr data1, IntPtr data2, int height, long significantBytes, int rowStride)
{
    while (height-- > 0) {
        if (memcmp(data1, data2, significantBytes) != 0) return false;
        data1 = IntPtr.Add(data1, rowStride);
        data2 = IntPtr.Add(data2, rowStride);
    }
    return true;
}