比较两张图片的差异

来源:互联网 发布:手机测防水软件 编辑:程序博客网 时间:2024/05/13 19:01

工作中经常遇到比较图片的需求,所以去网上搜索了一下,自己写了两个方法:


1. 直接使用Bitmap类对图片的每一个像素进行比较。

优点:简单

缺点:速度慢,当图片尺寸稍大的时候就会很慢(我的方法RemoveSinglePoints性能比较差,当存在差异的像素过多时会花费几十秒)

/// <summary>/// Compare two images./// </summary>/// <param name="img1">The first image path.</param>/// <param name="img2">The second image path.</param>/// <param name="imgDiff">The compare result image path.</param>/// <param name="tolerance">The compare tolerance.</param>/// <returns>If the two image are identical return true, else return false.</returns>private bool CompareImage(string img1, string img2, string imgDiff, int tolerance = 10){    // Load the images.    Bitmap bm1 = (Bitmap)Bitmap.FromFile(img1);    Bitmap bm2 = (Bitmap)Bitmap.FromFile(img2);    // Make a difference image.    if (bm1.Width != bm2.Width || bm1.Height != bm2.Height)    {        Console.WriteLine("Image size are different.");    }    int wid = bm1.Width;    int hgt = bm1.Height;    Bitmap bm3 = new Bitmap(bm1);    // Create the difference image.    Color ne_color = Color.Red;    List<Point> differentPoints = new List<Point>();    for (int x = 0; x < wid; x++)    {        for (int y = 0; y < hgt; y++)        {            if (!bm1.GetPixel(x, y).Equals(bm2.GetPixel(x, y)))            {                differentPoints.Add(new Point(x, y));            }        }    }    List<Point> continuousPoints = this.RemoveSinglePoints(differentPoints);    if (continuousPoints.Count <= tolerance)    {        return true;    }    foreach (var point in continuousPoints)    {        bm3.SetPixel(point.X, point.Y, ne_color);    }    bm3.Save(imgDiff);    return false;}


下面这个方法是防止一个孤立的像素点的不同导致程序认为两张图片不相同(我认为如果简单的一个像素不相同那么两张图片仍相同)
/// <summary>/// Remove all single point./// </summary>/// <param name="points">All points.</param>/// <returns>The continus points.</returns>public List<Point> RemoveSinglePoints(List<Point> points){    List<Point> continuousPoints = new List<Point>();    foreach (Point p in points)    {        var count = points.FindAll(x => Math.Abs(x.X + x.Y - p.X - p.Y) <= 2).Count;        if (count > 1)        {            continuousPoints.Add(p);        }    }    return continuousPoints;}


2. 下面的方法是使用BitmapData对图片进行比较,速度还是很快的。

这个方法的原理就是将整张图片的像素读取到一个列表中,然后比较两个列表的全部内容,发现不同的像素后将其替换为红色(RGB法), 24bit RGB法存储的图片每一个像素为3个字节,第一个字节是蓝色,第二个是绿色,第三个是红色(这个blog讲的很清楚,想详细了解的可以参考一下: http://blog.csdn.net/lulu831110/article/details/4820377/ )

/// <summary>/// Compare two images./// </summary>/// <param name="img1">The first image path.</param>/// <param name="img2">The second image path.</param>/// <param name="imgDiff">The compare result image path.</param>/// <param name="tolerance">The compare tolerance.</param>/// <returns>If the two image are identical return true, else return false.</returns>private bool CompareImageFast(string img1, string img2, string imgDiff, int tolerance = 10){    try    {        // Load the images.        Bitmap bm1 = (Bitmap)Bitmap.FromFile(img1);        Bitmap bm2 = (Bitmap)Bitmap.FromFile(img2);        int wid = bm1.Width;        int hgt = bm1.Height;        //// Make a difference image.        if (wid != bm2.Width || hgt != bm2.Height)        {            Console.WriteLine("Image size are different.");        }        BitmapData data1 = bm1.LockBits(new Rectangle(0, 0, wid, hgt), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);        BitmapData data2 = bm2.LockBits(new Rectangle(0, 0, wid, hgt), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);        //// Create the difference image.        Color ne_color = Color.Red;        int differentPoints = 0;        unsafe        {            //// Get the address of the first line of picture 1.             IntPtr ptr1 = data1.Scan0;            //// Declare an array to hold the bytes of the bitmap.             int bytes = data1.Stride * hgt;            byte[] rgbValues1 = new byte[bytes];            //// Copy the RGB values into the array.             System.Runtime.InteropServices.Marshal.Copy(ptr1, rgbValues1, 0, bytes);            //// Get the address of the first line of picture 2.             IntPtr ptr2 = data2.Scan0;            //// Declare an array to hold the bytes of the bitmap.             byte[] rgbValues2 = new byte[bytes];            //// Copy the RGB values into the array.             System.Runtime.InteropServices.Marshal.Copy(ptr2, rgbValues2, 0, bytes);            for (int counter = 0; counter < rgbValues1.Length; counter += 3)            {                if (rgbValues1[counter] != rgbValues2[counter] || rgbValues1[counter + 1] != rgbValues2[counter + 1] || rgbValues1[counter + 2] != rgbValues2[counter + 2])                {                    differentPoints++;                    rgbValues1[counter] = 0;                    rgbValues1[counter + 1] = 0;                    rgbValues1[counter + 2] = 255;                }            }            if (differentPoints <= tolerance)            {                return true;            }            //// Copy the RGB values back to the bitmap             System.Runtime.InteropServices.Marshal.Copy(rgbValues1, 0, ptr1, bytes);            bm1.UnlockBits(data1);            //// Save the different picture.            bm1.Save(imgDiff);            return false;        }    }    catch (Exception exp)    {        throw exp;    }}


0 0
原创粉丝点击