图片比较算法

上一篇 / 下一篇  2008-12-31 11:11:32 / 个人分类:自动化测试框架

前几天其他项目组接了个项目,客户那边要求顺便给做个图片比较的工具,因为他们要看看同样的网页在IE7和IE8上显示有什么不同,不同的地方用用户指定的某种颜色标示出来,生成第三张图片。因为他们组比较忙,就帮他们做了做,UI界面就不用说了。

起初的想法是这样,先比较两幅图片的hash散列,如果相同就不比较了,下面就是这个算法:

        /// <summary>
        /// compare the hash value of two image files.
        /// </summary>
        /// <param name="leftImage"></param>
        /// <param name="rightImage"></param>
        /// <returns></returns>
        private static bool HashCompare(Bitmap leftImage, Bitmap rightImage)
        {
            if (leftImage.Size != rightImage.Size)
            {
                return false;
            }

            byte[] buffer = new byte[1];
            byte[] buffer2 = new byte[1];
            ImageConverter converter = new ImageConverter();
            buffer = (byte[])converter.ConvertTo(leftImage, buffer.GetType());
            buffer2 = (byte[])converter.ConvertTo(rightImage, buffer2.GetType());
            SHA256Managed managed = new SHA256Managed();
            byte[] buffer3 = managed.ComputeHash(buffer);
            byte[] buffer4 = managed.ComputeHash(buffer2);

            for (int i = 0; (i < buffer3.Length) && (i < buffer4.Length); i++)
            {
                if (buffer3[i] != buffer4[i])
                {
                    return false;
                }
            }

            return true;
        }

如果hash散列不同,就挨个像素比较,可这样有个问题,就是两幅图片有时候其实我们看起来是一样的,但是实际上你取他们像素的时候他们是不同的,如果我们将用户都不能分辨出不同的地方都标示出来意义不大,于是最后决定只比较像素的R.G.B,只要他们相同就行(这里的相同也做了妥协,就是两个像素的R.G.B值也允许有一定的误差),最后算法如下:

   /// <summary>
        /// compare two bitmaps.
        /// </summary>
        /// <param name="leftImage">the first bitmap</param>
        /// <param name="rightImage">the second bitmap</param>
        /// <param name="resultImageFullPath">the result bitmap</param>
        /// <returns>return the comparision result</returns>
        public static bool Compare(Bitmap leftImage, Bitmap rightImage, string resultImageFullPath)
        {
            bool matched = true;

            //if the two bitmaps are not the same size,then resize the large one.
            if (leftImage.Height > rightImage.Height)
            {
                leftImage = BitMapAdapter.ResizeImage(leftImage, rightImage.Width, rightImage.Height);
            }
            else
            {
                rightImage = BitMapAdapter.ResizeImage(rightImage, leftImage.Width, leftImage.Height);
            }

            if (!HashCompare(leftImage, rightImage))
            {
                BitmapData leftBitmapdata = leftImage.LockBits(new Rectangle(0, 0, leftImage.Width, leftImage.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                BitmapData rightBitmapdata = rightImage.LockBits(new Rectangle(0, 0, rightImage.Width, rightImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

                unsafe
                {
                    byte* leftImageDataPointer = (byte*)(leftBitmapdata.Scan0.ToPointer());
                    byte* rightImageDataPointer = (byte*)(rightBitmapdata.Scan0.ToPointer());

                    for (int y = 0; y < leftBitmapdata.Height; y++)
                    {
                        for (int x = 0; x < leftBitmapdata.Width; x++)
                        {
                            if (Math.Abs((int)leftImageDataPointer[0] - (int)rightImageDataPointer[0]) > RGBDifference &&
                                Math.Abs((int)leftImageDataPointer[1] - (int)rightImageDataPointer[1]) > RGBDifference &&
                                Math.Abs((int)leftImageDataPointer[2] - (int)rightImageDataPointer[2]) > RGBDifference)
                            {
                                matched = false;
                                leftImageDataPointer[0] = (byte)mismatchedColor.B;
                                leftImageDataPointer[1] = (byte)mismatchedColor.G;
                                leftImageDataPointer[2] = (byte)mismatchedColor.R;
                            }

                            leftImageDataPointer += 3;
                            rightImageDataPointer += 3;
                        }

                        leftImageDataPointer += leftBitmapdata.Stride - leftBitmapdata.Width * 3;
                        rightImageDataPointer += rightBitmapdata.Stride - rightBitmapdata.Width * 3;
                    }
                }

                leftImage.UnlockBits(leftBitmapdata);
                rightImage.UnlockBits(rightBitmapdata);

                if (!matched)
                {
                    leftImage.Save(resultImageFullPath, ImageFormat.Jpeg);
                }

                return matched;
            }
            else
            {
                return true;
            }
        }

但是最后又出来个问题,因为对同一个网页,IE7跟IE8上显示的竟然不是同一个尺寸,最后就又加了一个调整尺寸的函数(上面红色的就是后来加的),调整函数如下:

        /// <summary>
        /// Resize bitmap
        /// </summary>
        /// <param name="bmp">original Bitmap</param>
        /// <param name="newW">new width</param>
        /// <param name="newH">new height</param>
        /// <returns>worked bitmap</returns>
        public static Bitmap ResizeImage(Bitmap bmp, int newW, int newH)
        {
            try
            {
                Bitmap bmap = new Bitmap(newW, newH);
                Graphics graph = Graphics.FromImage(bmap);
                graph.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graph.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
                graph.Dispose();

                return bmap;
            }
            catch
            {
                return null;
            }
        }


TAG: 自动化测试框架

Iris 引用 删除 xwzhaojing   /   2009-05-21 14:02:31
为什么我在VS2005中调试的时候会出现
“错误        1        当前上下文中不存在名称“BitMapAdapter”        C:\Documents and Settings\zhaojing\My Documents\Visual Studio 2005\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs        54        29        ConsoleApplication1
”之类的错误? 是不是还有什么别的文件没有放上来?
 

评分:0

我来说两句

Open Toolbar