libpuzzle の Perl binding である Image::Libpuzzle を使って関連画像を実装してみた。pHash や avgHash も試してみたけど、どれが良いかというとなんともいえない。
現像パラメータ違いみたいな写真同士のものはちゃんとスコアが高く出ている気がするが、それ以外の場合はいまいち似ているとは言えないような感じで、いまいちよくわからない。基本的に同一画像判定用な気がするので、あまり大きな期待はできなそう。
SQLite スキーマ
CREATE TABLE images (
`id` INTEGER PRIMARY KEY,
`uri` TEXT NOT NULL,
`entry_id` INTEGER NOT NULL,
`sig` BLOB NOT NULL
);
CREATE UNIQUE INDEX index_images_uri ON images (`uri`, `entry_id`);
CREATE TABLE ngram (
image_id INTEGER NOT NULL,
word BLOB NOT NULL,
PRIMARY KEY (`image_id`, `word`)
) WITHOUT ROWID;
CREATE INDEX index_word_image_id ON ngram (`word`, `image_id`);
こういう感じのスキーマ。複数のエントリに同じURLを貼ると無駄になるけど滅多にないので気にしない。
実装
Service::SimilarImage にだいたいまとめて実装した。SQL 自体は php - Libpuzzle Indexing millions of pictures? - Stack Overflow に書いてあるのとほぼ同じ。