Intereting Posts

Libpuzzle Индексирование миллионов изображений?

его о 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"; } 

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

Я прочитал readme из libbay lib и нашел следующее:

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

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

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

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

Итак, библиотека «Головоломка», безусловно, несовместима с проектами, которые должны индексировать миллионы изображений.

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

———————— УКАЗАНИЯ ————————

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

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

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

[ АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯ ]

При длине слова (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.

Приветствия.

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

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

 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 , что приведет к дальнейшему уменьшению вашего соответствия.

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

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

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

В любом случае, глядя сейчас, постараюсь предложить свое понимание – возможно, между нами мы сможем это сделать 🙂

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

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

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

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

… в теории все равно …

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

 // 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); } 

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

Проект использует то, что предложил Джейсон выше.

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


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

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

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

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

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

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

….


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