Libpuzzle Индексирование миллионов фотографий? - PullRequest
22 голосов
/ 14 марта 2012

речь идет о libpuzzle libray для php (http://libpuzzle.pureftpd.org/project/libpuzzle) от мистера Фрэнка Дениса.Я пытаюсь понять, как индексировать и хранить данные в моей базе данных MySQL.Генерация вектора абсолютно не проблема.

Пример:

# Compute signatures for two images
$cvec1 = puzzle_fill_cvec_from_file('img1.jpg');
$cvec2 = puzzle_fill_cvec_from_file('img2.jpg');

# Compute the distance between both signatures
$d = puzzle_vector_normalized_distance($cvec1, $cvec2);

# Are pictures similar?
if ($d < PUZZLE_CVEC_SIMILARITY_LOWER_THRESHOLD) {
  echo "Pictures are looking similar\n";
} else {
  echo "Pictures are different, distance=$d\n";
}

Это все мне ясно - но как мне работать, когда у меня большое количество фотографий> 1.000.000?Я рассчитать вектор и сохранить его с именем файла в базе данных?Как найти похожие картинки сейчас?Если я сохраняю каждый вектор в mysql, я должен открыть каждую запись и рассчитать расстояние с помощью функции puzzle_vector_normalized_distance.Эта процедура занимает много времени (откройте каждую запись базы данных - поставьте ее, бросьте функцию, ...)

Я прочитал readme из lib liby головоломки lib и обнаружил следующее:

Будет ли он работать с базой данных, содержащей миллионы изображений?

Типичная подпись изображения требует только 182 байта, используя встроенные функции сжатия / распаковки.

Подобные подписи имеют одинаковые «слова»», Т.е.идентичные последовательности значений в одинаковых позициях.При использовании составных индексов (слово + позиция) набор возможных похожих векторов значительно сокращается, и в большинстве случаев фактически не требуется вычислять векторное расстояние.

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

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

Также я нашел это описаниеиндексирование:

------------------------ INDEXING ------------------------

Как быстро найти похожие картинки, если их миллионы записей?

Оригинальный документ имеет простой, но эффективный ответ.

Вырезать вектор в словах фиксированной длины.Например, давайте рассмотрим следующий вектор:

[abcdefghijklmnopqrstu vwxyz]

С длиной слова (K), равной 10, вы можете получить следующие слова:

[abcdefghij] найден в позиции 0 [bcdefghijk] найден в позиции 1 [cdefghijkl] найден в позиции 2 и т. д. до позиции N-1

Затем индексируйте свой вектор с помощью составного индекса (слово + позиция).

Даже с миллионами изображений K = 10 и N = 100 должно быть достаточно, чтобы очень мало записей с одинаковым индексом.

Вот очень простой пример схемы базы данных:

+-----------------------------+
| signatures |
+-----------------------------+
| sig_id | signature | pic_id |
+--------+-----------+--------+

+--------------------------+
| words |
+--------------------------+
| pos_and_word | fk_sig_id |
+--------------+-----------+

Я бы рекомендовал разбить хотя бы таблицу слов на несколько таблиц и / или серверов.

По умолчанию (lambas = 9) сигнатуры имеют длину 544 байта.Чтобы сэкономить место на диске, их можно сжать до 1/3 их первоначального размера с помощью функции puzzle_compress_cvec ().Перед использованием они должны быть распакованы с помощью puzzle_uncompress_cvec ().

Я думаю, что сжатие - это неправильный путь, поэтому мне нужно распаковать каждый вектор перед его сравнением.

Мой вопрос сейчас - какой способ обработки миллионов изображений и как их быстро и эффективно сравнить.Я не могу понять, как «обрезка вектора» должна помочь мне с моей проблемой.

Большое спасибо - может быть, я найду здесь кого-нибудь, кто работает с libpuzzle libaray.

Cheers.

Ответы [ 4 ]

14 голосов
/ 20 марта 2012

Итак, давайте посмотрим на пример, который они дают, и попробуем развернуть.

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

CREATE TABLE images (
    image_id INTEGER NOT NULL PRIMARY KEY,
    name TEXT,
    description TEXT,
    file_path TEXT NOT NULL,
    url_path TEXT NOT NULL,
    signature TEXT NOT NULL
);

Когда вы изначально вычисляете подпись, вы также собираетесь вычислить количество слов из подписи:

// this will be run once for each image:
$cvec = puzzle_fill_cvec_from_file('img1.jpg');
$words = array();
$wordlen = 10; // this is $k from the example
$wordcnt = 100; // this is $n from the example
for ($i=0; $i<min($wordcnt, strlen($cvec)-$wordlen+1); $i++) {
    $words[] = substr($cvec, $i, $wordlen);
}

Теперь вы можете поместитьэти слова в таблицу, определенную следующим образом:

CREATE TABLE img_sig_words (
    image_id INTEGER NOT NULL,
    sig_word TEXT NOT NULL,
    FOREIGN KEY (image_id) REFERENCES images (image_id),
    INDEX (image_id, sig_word)
);

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

// the signature, along with all other data, has already been inserted into the images
// table, and $image_id has been populated with the resulting primary key
foreach ($words as $index => $word) {
    $sig_word = $index.'__'.$word;
    $dbobj->query("INSERT INTO img_sig_words (image_id, sig_word) VALUES ($image_id,
        '$sig_word')"); // figure a suitably defined db abstraction layer...
}

Таким образом, ваши данные инициализированы, вы можете сравнительно легко получить изображения с подходящими словами:

// $image_id is set to the base image that you are trying to find matches to
$dbobj->query("SELECT i.*, COUNT(isw.sig_word) as strength FROM images i JOIN img_sig_words
    isw ON i.image_id = isw.image_id JOIN img_sig_words isw_search ON isw.sig_word =
    isw_search.sig_word AND isw.image_id != isw_search.image_id WHERE
    isw_search.image_id = $image_id GROUP BY i.image_id, i.name, i.description,
    i.file_path, i.url_path, i.signature ORDER BY strength DESC");

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

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

По сути, разделение и хранение слов таким образом позволяет вам выполнять грубую проверку расстояния без необходимости запускать специализированную функцию в сигнатуре.Рез.

3 голосов
/ 14 марта 2012

Я экспериментировал с libpuzzle раньше - дошел до вас. На самом деле не начать надлежащую реализацию. Также было неясно, как именно это сделать. (и отказался от проекта из-за нехватки времени - так что на самом деле не настаивал на этом)

В любом случае, глядя сейчас, попытаюсь предложить мое понимание - может быть, между нами мы сможем решить это:)

Запросы используют двухэтапный процесс -

  1. сначала вы используете таблицу words .
    1. возьмите «эталонное» изображение и определите его подпись.
    2. отработать составные слова,
    3. сверьтесь с таблицей words , чтобы найти все возможные совпадения. Это может использовать «индексы» движков баз данных для эффективных запросов.
    4. составить список всех sig_ids. (получит несколько дубликатов в 3.)
  2. Затем обратитесь к таблице подписи
    1. получить и распаковать все возможные из подписей (поскольку у вас есть предварительно отфильтрованный список, число должно быть относительно небольшим)
    2. используйте puzzle_vector_normalized_distance для определения фактического расстояния.
    3. сортировка и ранжирование результатов по мере необходимости

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

Таблица words является формой инвертированного индекса. На самом деле я имею в виду использовать https://stackoverflow.com/questions/tagged/sphinx вместо таблицы базы данных слов, потому что она разработана специально как очень быстрый инвертированный индекс.

... теоретически все равно ...

1 голос
/ 02 ноября 2014

Я также работаю над libpuzzle в php и у меня есть некоторые сомнения относительно того, как генерировать слова из сигнатур изображений. Ответ Джейсона выше кажется правильным, но у меня есть проблема с этой частью:

// this will be run once for each image:
$cvec = puzzle_fill_cvec_from_file('img1.jpg');
$words = array();
$wordlen = 10; // this is $k from the example
$wordcnt = 100; // this is $n from the example
for ($i=0; $i<min($wordcnt, strlen($cvec)-$wordlen+1); $i++) {
    $words[] = substr($cvec, $i, $wordlen);
}

Вектор сигнатуры имеет длину 544 буквы, и с учетом вышеизложенного создания слов мы всегда используем только его первые 110 букв. Это означает, что мы индексируем от имени верхней трети содержимого изображения, если я правильно понимаю.

Если вы читаете оригинальную статью ( Подпись изображения для любого типа изображения ), на которой основан libpuzzle, они объясняют, что слова должны быть сгенерированы " ... возможно, несмежно и перекрывающиеся". Я не уверен, имеют ли они в виду несмежные и непересекающиеся или несмежные и пересекающиеся ...

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

Хотелось бы услышать, как вы, ребята, это понимаете.

0 голосов
/ 08 мая 2013

Я создал проект libpuzzle DEMO на GitHub: https://github.com/alsotang/libpuzzle_demo.

В проекте используется способ, предложенный Джейсоном выше.

Схема базы данных показывает: https://github.com/alsotang/libpuzzle_demo/blob/master/schema.sql


И я дам больше информации о подписи libpuzzle.

enter image description here enter image description here

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

enter image description here

Нечетные строки для изображения 1 (левого), а четные строки для изображения 2.

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

....


Мой английский настолько плохой, что я не могу выразить свое мнение, продолжайте ... Я думаю, что любой, кто захочетИндекс миллионы изображений должны проверить мое GitHub репозиторий DEMO ..

...