Подтвердить что ты не робот

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

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

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

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

введите описание изображения здесь введите описание изображения здесь

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

4b9b3361

Ответ 1

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

  • измените размер изображения на 16x16.

16x16 resized

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

введите описание изображения здесь

  1. читайте логические значения в 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% - другим.

Обновление/впечатления:

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

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

  • Те изображения одинаковы (первый из них не является частью второго или наоборот)
  • Изображения поворачиваются только на 90 градусов

Один из способов сравнения -

  • Измените размер изображения на минимальный размер.
  • Применить обнаружение края на каждом изображении, получая черно-белое изображение (или массив из 0 и 1)
  • Сравните полученные растровые изображения (сначала сохраните один и поверните второй на 90 градусов 3 раза) и рассчитайте% соответствия пикселов и получите наивысшее значение

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

  • Даже если разница в нескольких пикселях в углу, например, второе изображение обрезается с первого раза
  • Изображения вращаются, кроме кратных 90 градусов (хотя это маловероятно)