Использование MinHash, чтобы найти сходство между 2 изображениями

Я использую алгоритм MinHash для поиска похожих изображений между изображениями. Я столкнулся с этим сообщением, How can I recognize slightly modified images?, который указал мне на алгоритм MinHash.

Я использовал реализацию С# из этого сообщения в блоге, Set Similarity and Min Hash.

Но при попытке использовать реализацию я столкнулся с двумя проблемами.

  • Какое значение следует установить для значения universe для?
  • При передаче массива байтов изображения в HashSet он содержит только отдельные байтовые значения; таким образом, сравнивая значения от 1 до 256.

Что это за universe в MinHash?

И что я могу сделать для улучшения реализации С# MinHash?

Так как HashSet<byte> содержит значения до 256, значение подобия всегда выходит в 1.

Вот источник, который использует реализацию С# MinHash из Set Similarity and Min Hash:

class Program
{
    static void Main(string[] args)
    {
        var imageSet1 = GetImageByte(@".\Images\01.JPG");
        var imageSet2 = GetImageByte(@".\Images\02.TIF");
        //var app = new MinHash(256);
        var app = new MinHash(Math.Min(imageSet1.Count, imageSet2.Count));
        double imageSimilarity = app.Similarity(imageSet1, imageSet2);
        Console.WriteLine("similarity = {0}", imageSimilarity);
    }

    private static HashSet<byte> GetImageByte(string imagePath)
    {
        using (var fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
        using (var br = new BinaryReader(fs))
        {
            //List<int> bytes = br.ReadBytes((int)fs.Length).Cast<int>().ToList();
            var bytes = new List<byte>(br.ReadBytes((int) fs.Length).ToArray());
            return new HashSet<byte>(bytes);
        }
    }
}

Ответ 1

Сначала возьмем второй вопрос:

И что я могу сделать для улучшения реализации С# MinHash?

Вы пытаетесь сравнить изображения на уровне byte для файлов, которые по своей сути структурированы очень по-разному (вы используете TIFF как одно изображение, а GIF - в другом). Даже если визуально эти файлы были точно такими же, ваша реализация никогда не найдет дубликаты, если файлы не имеют один и тот же тип.

Тем не менее, ваша реализация minhash должна зависеть от сопоставимых атрибутов изображений, которые вы используете для создания подписей.

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

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

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

Возьмем, к примеру, следующие изображения:

red, greenred, green

Они равны 100px x 100px с 50 пикселями красного и 50 пикселей зеленого цвета.

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

Legend:
    g = green
    r = red

left image = { r, g }
right image = { r, g }

similarity = intersection(left, right) / union(left, right)

similarity = 1 / 1 = 100%

Заметка о представлении right image = { r, g }: потому что наборы неупорядочены, { r, g } совпадает с { g, r }, поэтому они действуют, то же самое, даже если вычисление Jaccard не вычисляется, этот момент делает очевидным.

Но, очевидно, эти изображения не совпадают.

Вот почему shingling обычно используется для поиска отдельных мини-регионов внутри набора, которые могут использоваться совместно, чтобы однозначно идентифицировать пункт.

Для изображений вы можете использовать последовательные значения RGB (в этом случае, перемещаясь слева направо, сверху вниз, обертывая при ударе края) фиксированной длины для генерации черепицы. В этом случае, если длина гальки равна трем, ваши наборы выглядят так (обратите внимание, что я использую квадратные скобки для обозначения атрибутов/векторов, поскольку черепица сама по себе не содержит):

left image = { [r, r, r], [r, r, g], [r, g, g], [g, g, g] }
right image = { [g, g, g], [g, g, r], [g, r, r], [r, r, r] } 

И дает вам сходство с Jaccard:

intersection(left, right) = 2
union(right, left) = 6

similarity(left, right) = 2 / 6 = 33.33%

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

Обратите внимание, что черепица может быть любой длины, которую вы выберете. Вам нужно будет решить, какие черепицы создают подходящие результаты сходства с Jaccard (и порог), чтобы ответить на вопрос "насколько похожи эти?"

Теперь, отвечая на ваш первый вопрос:

что такое значение юниверса?

В этом конкретном случае это количество элементов, которые могут существовать во Вселенной. Если вы использовали одиночные пиксели RGB, юниверс был бы:

255 * 255 * 255 = 16,581,375

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

Если вы знаете количество возможных элементов в юниверсе элементов, то это может помочь вам генерировать хэш-функции, которые уменьшают количество столкновений.

В реализации которую вы ссылаетесь, этот размер юниверса используется для генерации случайного числа, а затем передает эти числа для генерации нескольких хеш-функций для миниатюр что в идеале приведет к минимальным столкновениям.

Ответ 2

Вкратце, только Минхаш - плохое решение для поиска похожих изображений. При использовании в сочетании с соответствующим извлечением функции изображения, оно должно работать хорошо. Но это далеко не так просто. Я объясню:

Вообще говоря, Minhash рассчитывает сходство на основе количества общих функций. Выбор подходящих функций для создания ваших мини-хэшей очень важен. В вашем случае вы должны выбрать функции, которые, вероятно, будут использоваться одинаковыми изображениями (но вряд ли будут использоваться разными изображениями). Под "общим" я подразумеваю одинаковую функцию, одинаково обнаруженную на обоих изображениях.

Для текстовых документов это легко: обычно используются такие элементы, как черепица, например "сидел кот", "сидел кот", "сидел на коврике". Они просты в генерировании и могут использоваться совместно с похожими документами.

С изображениями это намного сложнее. Вы не можете сравнивать серии байтов, так как JPEG и PNG одного и того же изображения будут иметь совершенно разные шаблоны байтов. Вы также не можете сравнивать серии значений цвета пикселей, так как эти значения цвета будут немного отличаться между изображениями JPEG и PNG. А затем подумайте, что произойдет, если одно изображение будет немного масштабировано, размыто или слегка повернуто, или будет отрегулирован его цветовой баланс: это все виды модификаций, против которых должно быть устойчиво обнаружение сходства, но любое из них приведет к изменениям для всех пикселей, поэтому, если функции основаны просто на серии пикселей, изображения будут считаться совершенно не похожими.

Обнаружение сходства изображений является сложным и основано на использовании функций, которые не изменяются при масштабировании, повороте, кадрировании, размытии или существенных корректировках цвета. Есть много методов, и они обычно обнаруживают широкие формы и цветовые отношения в изображении. Это не для новичка, и вы должны быть готовы прочитать некоторые довольно математические статьи в области компьютерного зрения. Как только вы сможете обнаружить такие функции, они могут быть полезны для алгоритма minhash и дают хорошие результаты.

Что это за вселенная в MinHash?

Этот автор блога, по-видимому, намеревается universeSize число различных функций, которые могут когда-либо существовать, но ничего не делает с этим значением. Они просто используют его для уменьшения случайности хеш-функций, что всегда является плохой идеей. Вселенную следует рассматривать как бесконечную для всех практических целей, и нет никакой причины использовать такую переменную в реализации с минимальным хешем. Я вижу много проблем в этом коде.