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

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";
}

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

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

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

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

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

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

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

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

------------------------ УКАЗАНИЕ ---------------------- -

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

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

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

[a b c d e f g h я j k l m n o p q r s t u v w x y z]

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

[a b c d e f g h я j], найденный в позиции 0 [b c d e f g h я j k] найденный в позиции 1 [c d e f g h я j k l], найденный в позиции 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.

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

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

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

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

... в теории в любом случае...

Ответ 3

Я также работаю над 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);
}

Ответ 4

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

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

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


И я расскажу больше о сигнатуре libpuzzle.

enter image description hereenter image description here

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

enter image description here

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

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

....


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