php*_*man 22 php mysql compare image similarity
它是关于Frank Denis先生的libpuzzle libray for 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";
}
Run Code Online (Sandbox Code Playgroud)
多数民众赞成在我看来 - 但现在当我有大量的图片> 1.000.000时,我如何工作?我计算向量并将其与文件名一起存储在数据库中?现在如何找到类似的图片?如果我在mysql中存储每个向量,我必须打开每个记录并使用puzzle_vector_normalized_distance函数计算距离.该过程需要很多时间(打开每个数据库条目 - 把它抛出函数,...)
我从lib puzzle libaray读了自述文件,发现了以下内容:
它是否适用于拥有数百万张图片的数据库?
典型的图像签名仅需要182个字节,使用内置的压缩/解压缩功能.
类似的签名共享相同的"单词",即.相同位置的相同值序列.通过使用复合索引(单词+位置),可能的相似矢量集显着减少,并且在大多数情况下,实际上不需要计算矢量距离.
通过单词和位置进行索引还可以轻松地将数据拆分为多个表和服务器.
所以,是的,Puzzle库与一些需要索引数百万张图片的项目并不相容.
我也找到了关于索引的描述:
------------------------ INDEXING ------------------------
如何快速找到类似图片,如果它们是数百万条记录?
原始论文有一个简单而有效的答案.
用固定长度的单词剪切矢量.例如,让我们考虑以下向量:
[abcdefghijklmnopqrstu vwxyz]
如果单词长度(K)为10,您可以得到以下单词:
[abcdefghij]发现位置0 [bcdefghijk]发现位置1 [cdefghijkl]位于第2位等位置,直到位置N-1
然后,使用复合索引(word + position)索引矢量.
即使有数百万张图像,K = 10和N = 100也足以让很少的条目共享相同的索引.
这是一个非常基本的示例数据库模式:
+-----------------------------+
| signatures |
+-----------------------------+
| sig_id | signature | pic_id |
+--------+-----------+--------+
+--------------------------+
| words |
+--------------------------+
| pos_and_word | fk_sig_id |
+--------------+-----------+
Run Code Online (Sandbox Code Playgroud)
我建议至少将"单词"表拆分成多个表和/或服务器.
默认情况下(lambas = 9)签名长度为544字节.为了节省存储空间,可以通过puzzle_compress_cvec()函数将它们压缩到原始大小的1/3.在使用之前,必须使用puzzle_uncompress_cvec()解压缩它们.
我认为压缩是错误的方式因为我必须在比较它之前解压缩每个向量.
我现在的问题是 - 处理数百万张图片以及如何快速有效地比较它们的方式.我不明白"切割矢量"应该如何帮助我解决问题.
非常感谢 - 也许我可以在这里找到一个与libpuzzle libaray合作的人.
干杯.
Jas*_*son 14
那么,让我们来看看他们给出的例子并尝试扩展.
假设您有一个表,用于存储与每个图像(路径,名称,描述等)相关的信息.在该表中,您将包含压缩签名的字段,在最初填充数据库时计算并存储.让我们定义那个表:
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
);
Run Code Online (Sandbox Code Playgroud)
当您最初计算签名时,您还将计算签名中的多个单词:
// 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);
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以将这些单词放入表中,由此定义:
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)
);
Run Code Online (Sandbox Code Playgroud)
现在你插入到那个表中,在前面找到单词的位置索引,这样你就可以知道一个单词匹配在签名中相同位置匹配的单词:
// 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...
}
Run Code Online (Sandbox Code Playgroud)
您的数据如此初始化,您可以相对轻松地抓取匹配单词的图像:
// $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");
Run Code Online (Sandbox Code Playgroud)
您可以通过添加HAVING
需要最小值的子句来改进查询strength
,从而进一步减少匹配集.
我不保证这是最有效的设置,但它应该大致功能性来完成你正在寻找的东西.
基本上,以这种方式拆分和存储单词允许您进行粗略的距离检查,而无需在签名上运行专门的功能.
我以前尝试过 libpuzzle - 和你一样。并没有真正开始正确的实施。也不清楚具体该怎么做。(由于缺乏时间而放弃了该项目 - 所以并没有真正坚持下去)
不管怎样,现在看看,我会尽力提供我的理解——也许我们之间可以解决这个问题:)
查询使用 2 阶段过程 -
(即您只对签名表使用压缩。单词保持未压缩状态,因此可以对其运行快速查询)
Words表是倒排索引的一种形式。事实上,我打算使用/sf/ask/tagged/sphinx/代替单词数据库表,因为它是专门设计为非常快的倒排索引的。
...无论如何理论上...