его о 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 раньше – дошел до вас. На самом деле не началась правильная реализация. Было также непонятно, как именно это сделать. (и отказался от проекта из-за нехватки времени), так что на самом деле он не сохранился)
В любом случае, глядя сейчас, постараюсь предложить свое понимание – возможно, между нами мы сможем это сделать 🙂
Запросы используют двухэтапный процесс –
(т. е. вы используете только сжатие в таблице подписи, слова остаются несжатыми, поэтому могут запускать быстрые запросы на нем)
Таблица слов – это форма инвертированного индекса. На самом деле я имею в виду использовать 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 ..