【问题标题】:How to compare two images?如何比较两张图片?
【发布时间】:2019-09-08 00:33:07
【问题描述】:
public void winCheck()
{
    if (button1.Image == img1)
    {
        w1 = "P2";
        button1.Image = new Bitmap(@"win_cross.png");
        button2.Image = new Bitmap(@"win_cross.png");
        button3.Image = new Bitmap(@"win_cross.png");
    }
}

这里button1.Imageimg1 都有相同的图像,但控件仍然没有进入if 块。 它们是否具有两者的任何属性,使得两者的值相同。

【问题讨论】:

  • 您是不是想说图像是相同的,因为它们的比特位相同(它们显示相同的图像)?如何初始化 button1.Image 和 img1 变量?
  • 实际上它们是每个位相同的图像位,我已经在 button1 单击事件处理程序中初始化了 button1.Image,并且我在主类本身中创建了 img1(Image)(public) 变量。
  • Comparing Images 的可能重复项
  • 这是非常糟糕的编码,无法依靠图形元素来保持状态并测试这些状态。相反,您应该为各种状态定义一个枚举,使用此枚举键入一个字段,并定义一个根据字段枚举值刷新控件图像的方法。

标签: c# .net


【解决方案1】:

如果您可以拥有unsafe 代码并且如果您希望图像在字节级别上完全相同,这是一种可能性:

public unsafe static bool AreEqual(Bitmap b1, Bitmap b2)
{
    if (b1.Size != b2.Size)
    {
        return false;
    }

    if (b1.PixelFormat != b2.PixelFormat)
    {
        return false;
    }

    if (b1.PixelFormat != PixelFormat.Format32bppArgb)
    {
        return false;
    }

    Rectangle rect = new Rectangle(0, 0, b1.Width, b1.Height);
    BitmapData data1
        = b1.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);
    BitmapData data2
        = b2.LockBits(rect, ImageLockMode.ReadOnly, b1.PixelFormat);

    int* p1 = (int*)data1.Scan0;
    int* p2 = (int*)data2.Scan0;
    int byteCount = b1.Height * data1.Stride / 4; //only Format32bppArgb 

    bool result = true;
    for (int i = 0; i < byteCount; ++i)
    {
        if (*p1++ != *p2++)
        {
            result = false;
            break;
        }
    }

    b1.UnlockBits(data1);
    b2.UnlockBits(data2);

    return result;
}

这会“从字面上”比较图像 - 所有字节都必须完全相同。其他可能性是比较像素的颜色 - 然后PixelFormats 不必相同(取自here):

public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
    CompareResult cr = CompareResult.ciCompareOk;

    //Test to see if we have the same size of image
    if (bmp1.Size != bmp2.Size)
    {
        cr = CompareResult.ciSizeMismatch;
    }
    else
    {
        //Sizes are the same so start comparing pixels
        for (int x = 0; x < bmp1.Width 
             && cr == CompareResult.ciCompareOk; x++)
        {
            for (int y = 0; y < bmp1.Height 
                         && cr == CompareResult.ciCompareOk; y++)
            {
                if (bmp1.GetPixel(x, y) != bmp2.GetPixel(x, y))
                    cr = CompareResult.ciPixelMismatch;
            }
        }
    }
    return cr;
}

然而,这可能非常缓慢。同一个链接包含一个比较哈希值的有趣想法:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Security.Cryptography;

namespace Imagio
{
    public class ComparingImages
    {
        public enum CompareResult
        {
            ciCompareOk,
            ciPixelMismatch,
            ciSizeMismatch
        };

        public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
        {
            CompareResult cr = CompareResult.ciCompareOk;

            //Test to see if we have the same size of image
            if (bmp1.Size != bmp2.Size)
            {
                cr = CompareResult.ciSizeMismatch;
            }
            else
            {
                //Convert each image to a byte array
                System.Drawing.ImageConverter ic = 
                       new System.Drawing.ImageConverter();
                byte[] btImage1 = new byte[1];
                btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
                byte[] btImage2 = new byte[1];
                btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());

                //Compute a hash for each image
                SHA256Managed shaM = new SHA256Managed();
                byte[] hash1 = shaM.ComputeHash(btImage1);
                byte[] hash2 = shaM.ComputeHash(btImage2);

                //Compare the hash values
                for (int i = 0; i < hash1.Length && i < hash2.Length 
                                  && cr == CompareResult.ciCompareOk; i++)
                {
                    if (hash1[i] != hash2[i])
                        cr = CompareResult.ciPixelMismatch;
                }
            }
            return cr;
        }
    }
}

【讨论】:

    【解决方案2】:

    您的代码不起作用,因为您正在比较指向图像(即内存地址)而不是图像数据(像素)的变量。

    参见 ImageComparer.Compare 方法。具有指定容差的重载。 它从 VS2012 开始可用。

    https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.uitesting.imagecomparer.compare.aspx

    【讨论】:

      【解决方案3】:

      不要使用双等号 (==)。 使用等于方法。 (如果 button1.Image.equals(img1)) // 你编码

      【讨论】:

      • -1:位图未实现“等于”。它默认比较引用。
      • 它给出了 NullReferenceException - 对象引用未设置为对象的实例。
      • 那么您的一张图片为空。检查它@k3rn3l
      • @AsadAli 你为什么不自己测试一下? 位图 b1 = (Bitmap)Bitmap.FromFile(fname);位图 b2 = (Bitmap)Bitmap.FromFile(fname); var isEqual = b1.Equals(b2);
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 2022-12-15
      • 1970-01-01
      • 2019-07-17
      相关资源
      最近更新 更多