Как сравнить объекты Image с С#.NET?

Можно ли сравнить два объекта Image с С#? Например, проверьте, равны ли они или даже лучше проверьте, насколько похожи их пиксели?

если возможно, как?

Ответы

Ответ 1

Вы можете использовать набор инструментов под названием TestApi, который представляет собой библиотеку с открытым исходным кодом, помогающую модульному тестированию. Один из таких API называется API визуальной проверки, и он делает именно то, что вам нужно - он может сравнивать два изображения и сообщать вам, равны ли они:

// 1. Capture the actual pixels from a given window
Snapshot actual = Snapshot.FromRectangle(new Rectangle(0, 0, 100, 100));

// 2. Load the reference/master data from a previously saved file
Snapshot expected = Snapshot.FromFile("Expected.png"));

// 3. Compare the actual image with the master image
//    This operation creates a difference image. Any regions which are identical in 
//    the actual and master images appear as black. Areas with significant 
//    differences are shown in other colors.
Snapshot difference = actual.CompareTo(expected);

// 4. Configure the snapshot verifier - It expects a black image with zero tolerances
SnapshotVerifier v = new SnapshotColorVerifier(Color.Black, new ColorDifference());

// 5. Evaluate the difference image
if (v.Verify(difference) == VerificationResult.Fail)
{
    // Log failure, and save the diff file for investigation
    actual.ToFile("Actual.png", ImageFormat.Png);
    difference.ToFile("Difference.png", ImageFormat.Png);
}

Ответ 2

Простейшим местом для начала были бы размеры. Если размеры не равны, вы можете объявить их ложными.

Если вам нужно пройти через них пополам, вам понадобятся два цикла. Что-то в этом роде:

Bitmap ImageA...
Bitmap ImageB...

for ( Int64 x = 0; x < ImageA.Width; x++ )
{
     for ( Int64 y = 0; y < ImageA.Height; y++ )
     {
         if ( ImageA.GetPixel(x, y) != ImageB.GetPixel(x, y) )
         {
            return false;
         }
     }
}

Этот псевдокод (функции существуют в С#, хотя я не могу их вспомнить в данный момент) и очень упрощен, но как вы хотите выполнить базовую проверку пикселя в пиксель.

Обратите внимание, однако, что для этого цикла для работы изображения должны иметь одинаковую размерность. Если это не так, вы, скорее всего, получите исключения, если попытаетесь пробовать пиксель за пределами меньшей области. Также не будет очень быстро сравнивать пиксели, поэтому вам может понадобиться другой способ отбросить возможные дубликаты.

Изменить: я не уверен, как это сделать на Image, но это довольно просто для Bitmap s. Не существует видимого способа получения данных пикселя изображения из класса. Похоже, что растровые изображения наследуются от изображений, поэтому это может все еще работать. Учитывая, что изображения являются абстрактным классом для растровых изображений и метафайлов, у них может не быть простого внутреннего списка пикселей.

Ответ 3

У меня был тот же вопрос в тот же день, моим обходным решением было взять image1 и image2, преобразованные в 256x256 или 128x128, как переведенные, так и затем генерирующие image3 с разницей между ними, затем сканирование image3, проверяющее различия и возвращающее сумму разницы, Я узнал, что разница в LOWER в% больше равна изображениям и более вероятно, что они будут равны. Таким образом, вы можете определить, равны ли изображения, даже если они имеют разный размер. вот код.

double CompareImages(Bitmap InputImage1, Bitmap InputImage2, int Tollerance)
    {
        Bitmap Image1 = new Bitmap(InputImage1, new Size(128, 128));
        Bitmap Image2 = new Bitmap(InputImage2, new Size(128, 128));
        int Image1Size = Image1.Width * Image1.Height;
        int Image2Size = Image2.Width * Image2.Height;
        Bitmap Image3;
        if (Image1Size > Image2Size)
        {
            Image1 = new Bitmap(Image1, Image2.Size);
            Image3 = new Bitmap(Image2.Width, Image2.Height);
        }
        else
        {
            Image1 = new Bitmap(Image1, Image2.Size);
            Image3 = new Bitmap(Image2.Width, Image2.Height);
        }
        for (int x = 0; x < Image1.Width; x++)
        {
            for (int y = 0; y < Image1.Height; y++)
            {
                Color Color1 = Image1.GetPixel(x, y);
                Color Color2 = Image2.GetPixel(x, y);
                int r = Color1.R > Color2.R ? Color1.R - Color2.R : Color2.R - Color1.R;
                int g = Color1.G > Color2.G ? Color1.G - Color2.G : Color2.G - Color1.G;
                int b = Color1.B > Color2.B ? Color1.B - Color2.B : Color2.B - Color1.B;
                Image3.SetPixel(x, y, Color.FromArgb(r,g,b));
            }
        }
        int Difference = 0;
        for (int x = 0; x < Image1.Width; x++)
        {
            for (int y = 0; y < Image1.Height; y++)
            {
                Color Color1 = Image3.GetPixel(x, y);
                int Media = (Color1.R + Color1.G + Color1.B) / 3;
                if (Media > Tollerance)
                    Difference++;
            }
        }
        double UsedSize = Image1Size > Image2Size ? Image2Size : Image1Size;
        double result = Difference*100/UsedSize;
        return Difference*100/UsedSize;
    }

Протестировано здесь с более чем 900 изображениями и работает как шарм x)