Алгоритм сравнения двух изображений в C#

Я пишу инструмент на C#, чтобы найти дубликаты изображений. В настоящее время я создаю контрольную сумму MD5 файлов и сравнить их.

к сожалению, мои изображения могут быть

  • повернуть на 90 градусов
  • имеют разные размеры (меньшее изображение с одинаковым содержанием)
  • имеют различные сжатия или типы файлов (например, артефакты jpeg, см. ниже)

enter <a href=image description here" src="/images/content/35151067/d9157618d5117c9e9f7594e812d77993.jpg">enter image description here

что был бы наилучший подход к решению этой проблемы?

4 ответов


вот простой подход с 256-битным хэшем изображения (MD5 имеет 128 бит)

  1. изменить размер изображения до 16x16 пикселей

16x16 resized

  1. уменьшить количество цветов до черный/белый (что составляет правда/false в этой консоли вывода)

enter image description here

  1. читать boolean значения в List<bool> - это хэш -

код:

public static List<bool> GetHash(Bitmap bmpSource)
{
    List<bool> lResult = new List<bool>();         
    //create new image with 16x16 pixel
    Bitmap bmpMin = new Bitmap(bmpSource, new Size(16, 16));
    for (int j = 0; j < bmpMin.Height; j++)
    {
        for (int i = 0; i < bmpMin.Width; i++)
        {
            //reduce colors to true / false                
            lResult.Add(bmpMin.GetPixel(i, j).GetBrightness() < 0.5f);
        }             
    }
    return lResult;
}

Я знаю, GetPixel не так быстро, но на пиксельном изображении 16x16 это не должно быть узким местом.

  1. сравните этот хэш с хэш-значениями из других изображений и добавьте допуск.(количество пикселей, которые могут отличаться от другого хэша)

код:

List<bool> iHash1 = GetHash(new Bitmap(@"C:\mykoala1.jpg"));
List<bool> iHash2 = GetHash(new Bitmap(@"C:\mykoala2.jpg"));

//determine the number of equal pixel (x of 256)
int equalElements = iHash1.Zip(iHash2, (i, j) => i == j).Count(eq => eq);

таким образом, этот код может найти равный изображения с:

  • различные форматы файлов (например, jpg, png, bmp)
  • вращение (90, 180, 270), горизонтальное /вертикальное сальто - путем изменения порядка итерации i и j
  • различные размеры (требуется один и тот же аспект)
  • различное сжатие (допуск требуется в случае потери качества, например, артефактов jpeg) - вы можете принять равенство 99%, чтобы быть одним и тем же изображением и 50%, чтобы быть другим.
  • цвета изменен на geyscaled и наоборот (потому что яркость не зависит от цвета)

Обновление / Улучшение:

после использования этого метода некоторое время я заметил несколько улучшений, которые можно сделать

  • замена GetPixel дополнительные показатели
  • С помощью exeif-миниатюра вместо чтения всего изображения для производительности улучшение
  • вместо 0.5f чтобы отличаться от светлого и темного-используйте различную среднюю яркость всех 256 пикселей. В противном случае предполагается, что темные/светлые изображения одинаковы, и это позволяет обнаруживать изображения с измененной яркостью.
  • если вам нужно быстро расчеты, использовать bool[] или List<bool> Если вам нужно хранить много хэшей с необходимостью сохранения памяти, используйте Bitarray поскольку логическое значение не сохраняется в бит, требуется байт!

вы можете проверить алгоритм сравнения двух изображений для того чтобы увидеть доступные методы для сравнения изображений.

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

для реализации C# с открытым исходным кодом обнаружения края и связанных алгоритмов компьютерного зрения, вы можете попробовать EmguCV, который является оберткой в формате OpenCV.


после повторной выборки изображений до некоторого общего разрешения вы можете использовать вейвлет-декомпозицию и сравнить коэффициенты этой декомпозиции вместо самих изображений. Сравнение только первых n коэффициентов сделает этот метод более надежным для шума и других артефактов.

существует несколько реализаций C# для вейвлетов. Одним из примеров являетсяhttps://waveletstudio.codeplex.com/


интересный вопрос, сравнение изображений, не так сложно, учитывая, что

  1. эти изображения одинаковы (первый не является разделом второго или наоборот)
  2. изображения поворачиваются только кратными 90 градусов

один из способов сделать сравнение будет,

  1. измените размер обоих изображений до наименьшего размера diamention
  2. применить обнаружение края на каждом изображении в результате черно-белого изображения (или массив 0 и 1)
  3. сравните результирующие растровые изображения (держите первый неподвижным и поверните второй на 90 градусов 3 раза) и вычислите % совпадающих пикселей и получите самое высокое значение

теперь, если значение находится в пределах разумного значения, скажем, 90% (вероятно, нужно определить, выполнив несколько экспериментов), то вы можете смело предположить, что оба одинаковы, но это не сработает, если,

  1. даже если несколько пикселей differece в углу, например второе изображение обрезается с первого
  2. изображения поворачиваются, кроме кратных 90 градусов (хотя это не очень вероятно)