Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Libpuzzle Millionen von Bildern indizieren?

Schauen wir uns also das Beispiel an, das sie geben, und versuchen wir, es zu erweitern.

Nehmen wir an, Sie haben eine Tabelle, in der Informationen zu jedem Bild gespeichert sind (Pfad, Name, Beschreibung usw.). In diese Tabelle fügen Sie ein Feld für die komprimierte Signatur ein, die berechnet und gespeichert wird, wenn Sie die Datenbank zum ersten Mal füllen. Lassen Sie uns diese Tabelle folgendermaßen definieren:

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

Wenn Sie die Signatur anfänglich berechnen, werden Sie auch eine Reihe von Wörtern aus der Signatur berechnen:

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

Jetzt können Sie diese Wörter in eine Tabelle einfügen, die folgendermaßen definiert ist:

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

Jetzt fügen Sie in diese Tabelle ein und stellen den Positionsindex voran, wo das Wort gefunden wurde, damit Sie wissen, wenn ein Wort übereinstimmt, dass es an derselben Stelle in der Signatur gefunden wurde:

// 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...
}

Ihre Daten so initialisiert, können Sie relativ einfach Bilder mit passenden Wörtern aufnehmen:

// $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");

Sie könnten die Abfrage verbessern, indem Sie einen HAVING hinzufügen Klausel, die eine Mindest-strength erfordert , wodurch Ihr Matching-Set weiter reduziert wird.

Ich kann nicht garantieren, dass dies das effizienteste Setup ist, aber es sollte ungefähr funktionieren, um das zu erreichen, wonach Sie suchen.

Im Grunde ermöglicht Ihnen das Aufteilen und Speichern der Wörter auf diese Weise eine grobe Entfernungsprüfung, ohne eine spezielle Funktion für die Signaturen ausführen zu müssen.