当前位置:首页 > 开发 > C# > 正文内容

C# 比较两个Image对象是否相同

C#2周前 (05-20)

方法思路

  1. 基础检查:先检查空引用和图像尺寸

  2. 像素格式验证:确保两个图像的像素格式相同

  3. 内存锁定:使用LockBits直接访问内存数据提升效率

  4. 逐行像素比较:考虑内存对齐的步幅(Stride)差异,逐行比较有效像素数据

实现代码

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

public class ImageComparer
{
    public static bool AreImagesEqual(Image image1, Image image2)
    {
        // 处理空引用情况
        if (image1 == null || image2 == null)
            return image1 == image2;

        // 快速尺寸检查
        if (image1.Size != image2.Size)
            return false;

        // 转换为Bitmap以便操作
        using (Bitmap bmp1 = new Bitmap(image1))
        using (Bitmap bmp2 = new Bitmap(image2))
        {
            // 检查像素格式
            if (bmp1.PixelFormat != bmp2.PixelFormat)
                return false;

            // 获取像素格式信息
            int bitsPerPixel = Image.GetPixelFormatSize(bmp1.PixelFormat);
            if (bitsPerPixel != Image.GetPixelFormatSize(bmp2.PixelFormat))
                return false;

            int bytesPerPixel = (bitsPerPixel + 7) / 8; // 向上取整
            int width = bmp1.Width;
            int height = bmp1.Height;

            // 锁定位图内存区域
            Rectangle rect = new Rectangle(0, 0, width, height);
            BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, bmp1.PixelFormat);
            BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, bmp2.PixelFormat);

            try
            {
                // 计算每行有效字节数
                int effectiveBytesPerRow = width * bytesPerPixel;
                int stride1 = Math.Abs(bmpData1.Stride);
                int stride2 = Math.Abs(bmpData2.Stride);

                // 准备行数据缓冲区
                byte[] row1 = new byte[effectiveBytesPerRow];
                byte[] row2 = new byte[effectiveBytesPerRow];

                IntPtr ptr1 = bmpData1.Scan0;
                IntPtr ptr2 = bmpData2.Scan0;

                // 逐行比较
                for (int y = 0; y < height; y++)
                {
                    Marshal.Copy(ptr1, row1, 0, effectiveBytesPerRow);
                    Marshal.Copy(ptr2, row2, 0, effectiveBytesPerRow);

                    if (!AreByteArraysEqual(row1, row2))
                        return false;

                    ptr1 = IntPtr.Add(ptr1, stride1);
                    ptr2 = IntPtr.Add(ptr2, stride2);
                }

                return true;
            }
            finally
            {
                bmp1.UnlockBits(bmpData1);
                bmp2.UnlockBits(bmpData2);
            }
        }
    }

    private static bool AreByteArraysEqual(byte[] a1, byte[] a2)
    {
        if (a1.Length != a2.Length)
            return false;

        for (int i = 0; i < a1.Length; i++)
        {
            if (a1[i] != a2[i])
                return false;
        }
        return true;
    }
}

使用示例

Image img1 = Image.FromFile("image1.png");
Image img2 = Image.FromFile("image2.jpg");

bool isEqual = ImageComparer.AreImagesEqual(img1, img2);
Console.WriteLine($"图像是否相同: {isEqual}");

注意事项

  • 像素格式要求:要求两个图像必须具有相同的像素格式(如Format24bppRgb、Format32bppArgb等)

  • 性能考虑:大尺寸图片比较可能较慢,建议在后台线程执行

  • 资源释放using语句确保Bitmap对象正确释放,避免内存泄漏

  • 特殊格式:不支持带调色板的索引格式(如Format8bppIndexed)

  • 图像来源:支持不同来源的图片(文件/内存/流),但必须能转换为Bitmap

如果需要处理不同格式的图像,建议先进行标准化转换:

using (Bitmap standardized = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppArgb))
{
    using (Graphics g = Graphics.FromImage(standardized))
    {
        g.DrawImage(source, 0, 0);
    }
    // 使用standardized进行比较
}

转载请注明出处。

本文链接:http://www.pythonopen.com/?id=7910

返回列表

上一篇:C# i++和++i的区别

没有最新的文章了...

相关文章

C# Byte[]转为Bitmap

在 C# 中,可以使用System.Drawing命名空间下的相关类将byte[]类型的数据转换为B...

C# MemoryStream转为Image

        //...

C# Graphics图像抗锯齿

g.SmoothingMode = SmoothingMode.AntiAlia...

C# i++和++i的区别

核心区别操作顺序            ...