Php 如何在SQL查询中通过相似性查找图像?

Php 如何在SQL查询中通过相似性查找图像?,php,mysql,sql,image,image-processing,Php,Mysql,Sql,Image,Image Processing,我想处理图像,比如说,在每个区域内建立9个区域,然后找到每个区域的平均颜色,然后将其保存到一个char字段,如下所示: 255,255,255,255,255,255,107,195,305 然后,为了找到与给定图像相似的所有图像,我必须计算每对颜色之间的距离(与相同区域进行比较),例如: 这些图像之间的差异为1: 255,255,255,255,255,255,107,195,305 255,255,255,255,255,255,107,195,304 这些图像之间的区别是3: 255,

我想处理图像,比如说,在每个区域内建立9个区域,然后找到每个区域的平均颜色,然后将其保存到一个char字段,如下所示:

255,255,255,255,255,255,107,195,305
然后,为了找到与给定图像相似的所有图像,我必须计算每对颜色之间的距离(与相同区域进行比较),例如:

这些图像之间的差异为1:

255,255,255,255,255,255,107,195,305
255,255,255,255,255,255,107,195,304
这些图像之间的区别是3:

255,255,255,255,255,255,105,195,305
255,255,255,255,255,255,107,195,304
255,255,255,255,255,255,105,195,305
255,255,255,255,255,255,107,195,304
我的问题是如何执行这样的查询,并按相似性排序?该字段只是一个字符串,值之间用逗号分隔

这样的查询是否可能很快?还是我应该寻找一种不同的方法?我们正在谈论成千上万的图像


编辑:作为@Theralsix,一个选项是将每个平均颜色值放在一个单独的列中。

实际上,从它的声音来看,您正在尝试进行一种形式的序列对齐。为此,使用了一系列算法来比较基因序列:


我想你在找这样的东西

注意右边的色差

Color Difference: 1.84568861095


如果同时有大量用户,在1000多行上运行此查询肯定会杀死服务器。

我建议使用mysql函数与随机给定的图像进行比较。首先让我们创建一个简单的示例表

DROP TABLE IF EXISTS images;

CREATE TABLE images (
  id         INTEGER AUTO_INCREMENT PRIMARY KEY,
  rgb_values VARCHAR(255)
);
现在让我们定义我们将在查询中使用的函数。第一个选项允许使用拆分任何分隔符上的字符串,并通过索引返回所需的元素:

DROP FUNCTION SPLIT_STR;

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255)
RETURN
  REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
  LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
  delim, '')
;
接下来,我们定义一个函数,根据您的算法(或您想要使用的任何算法)计算图像差异:

让我们创建一些示例数据:

INSERT INTO images(rgb_values) VALUES ("237,128,73,69,35,249,199,183,178");
INSERT INTO images(rgb_values) VALUES ("39,212,164,170,202,49,93,77,145");
INSERT INTO images(rgb_values) VALUES ("28,242,83,167,92,161,115,38,108");
INSERT INTO images(rgb_values) VALUES ("72,81,73,2,77,109,177,204,120");
INSERT INTO images(rgb_values) VALUES ("165,149,106,248,39,26,167,237,139");
INSERT INTO images(rgb_values) VALUES ("183,40,156,131,120,19,71,88,69");
INSERT INTO images(rgb_values) VALUES ("138,136,112,36,69,245,130,196,24");
INSERT INTO images(rgb_values) VALUES ("1,194,153,107,16,102,164,154,74");
INSERT INTO images(rgb_values) VALUES ("172,161,17,179,140,244,23,219,115");
INSERT INTO images(rgb_values) VALUES ("166,151,48,62,154,227,44,21,201");
INSERT INTO images(rgb_values) VALUES ("118,73,212,180,150,64,254,177,68");
INSERT INTO images(rgb_values) VALUES ("119,220,226,254,14,175,123,11,134");
INSERT INTO images(rgb_values) VALUES ("118,93,238,31,77,36,105,151,216");
INSERT INTO images(rgb_values) VALUES ("123,108,177,136,9,24,119,175,88");
INSERT INTO images(rgb_values) VALUES ("11,207,12,215,215,80,101,213,143");
INSERT INTO images(rgb_values) VALUES ("132,158,46,188,7,245,241,126,214");
INSERT INTO images(rgb_values) VALUES ("167,238,186,86,109,164,219,199,238");
INSERT INTO images(rgb_values) VALUES ("216,93,139,246,153,39,226,152,143");
INSERT INTO images(rgb_values) VALUES ("98,229,7,203,230,224,57,154,252");
INSERT INTO images(rgb_values) VALUES ("7,95,145,120,35,6,116,240,64");
INSERT INTO images(rgb_values) VALUES ("45,194,172,223,96,168,18,4,215");
INSERT INTO images(rgb_values) VALUES ("243,161,214,235,134,190,207,63,127");
INSERT INTO images(rgb_values) VALUES ("74,189,249,85,148,169,65,3,81");
INSERT INTO images(rgb_values) VALUES ("46,113,191,20,108,139,60,249,6");
INSERT INTO images(rgb_values) VALUES ("153,246,189,175,5,125,9,197,160");
INSERT INTO images(rgb_values) VALUES ("202,248,23,59,81,175,197,180,114");
INSERT INTO images(rgb_values) VALUES ("73,136,252,137,222,197,118,64,69");
INSERT INTO images(rgb_values) VALUES ("172,224,251,32,154,175,201,33,14");
INSERT INTO images(rgb_values) VALUES ("141,126,112,12,45,214,243,127,49");
INSERT INTO images(rgb_values) VALUES ("116,155,23,205,62,235,111,136,205");
然后使用新定义的函数对要比较的图像运行查询:

mysql> SELECT id
    ->      , image_diff(rgb_values, '255,191,234,123,85,23,255,255,255') rgb_diff
    ->   FROM images
    ->  ORDER BY 2 DESC;
+----+----------+
| id | rgb_diff |
+----+----------+
| 19 |     1150 |
| 10 |     1148 |
|  3 |     1122 |
| 27 |     1094 |
|  9 |     1070 |
| 15 |     1069 |
| 23 |     1061 |
| 21 |     1059 |
|  7 |     1034 |
| 12 |     1024 |
| 24 |     1022 |
| 30 |     1016 |
| 29 |      989 |
| 28 |      962 |
|  2 |      947 |
|  4 |      933 |
| 16 |      893 |
|  6 |      885 |
|  8 |      875 |
| 20 |      848 |
| 25 |      835 |
| 26 |      815 |
|  1 |      777 |
| 22 |      758 |
| 14 |      745 |
| 11 |      706 |
| 18 |      683 |
|  5 |      656 |
| 13 |      645 |
| 17 |      494 |
+----+----------+
30 rows in set (0.01 sec)

好的,所以您的表图像有一个id和9个单独的颜色字段-颜色1到颜色9

SELECT a.id, b.id, ( ABS( a.color1 - b.color ) + ABS( a.color2 + b.color2 ) + ABS( a.color3 + b.color3 ) + ... ) AS difference
FROM images AS a
JOIN images AS b
WHERE a.id > b.id
ORDER BY difference
这可能相当有效,您必须尝试一下。

更“SQLey”的方法是使用更规范化的数据库方法,包括两个表:

Image(ImageID int, ... other columns as required ...)
ImageZone(ImageID int, ZoneIndex int, ColourValue int, ...)
以你为例,你可能

ImageID   ZoneIndex   ColourValue
-------   ---------   -----------
  1          1          255
  1          2          255
  ...
  1          9          304
  2          1          255
  ...
  2          9          305
然后,为了获得距离,类似于(我是一个SQL Server的家伙,但这应该可以很容易地翻译成MySQL):

然后将其汇总为总差异:

 OriginalID  CandidateID  Difference
 ----------  -----------  ----------
    1            2            1
    1            3           10
    ...
    99          98          500
然后从这个虚拟表中进行选择,仅当OriginalID为1时,然后将其连接回原始图像表,以获得最低“差异”分数所需的任何详细信息(在本例中为2)


这是一个更干净的数据库设计(如果以后使用更多的区域等,则非常适合)。

在我看来,这个问题不是序列比较问题,而是地理问题

我想你想在第九维度的点集中找到附近的点

查看这篇文章,了解空间数据库如何使用R-树高效搜索簇(例如,附近的点正是您想要的。):(单击“缓存”链接)

真正的问题是,据我所知,并没有支持9维空间的空间数据库。我能想到的唯一一个技巧就是地理三元组(a,B,C)的点

让我的观点更清楚。让我们看看您的数据:

这些图像之间的区别是3:

255,255,255,255,255,255,105,195,305
255,255,255,255,255,255,107,195,304
255,255,255,255,255,255,105,195,305
255,255,255,255,255,255,107,195,304
我们可以将上述两行视为9维世界中的两个点(我们称它们为
a
b

这9个数字是它们的坐标(
a1、a2、…、a9和
b1、b2、…、b9

“差别”是它们之间的距离:
Sum(| ai bi |)
。定义距离的方法有很多,这是常见的方法之一。这不是欧几里得距离,但它是相似的。计算起来要快一点

现在,如果你真的要有数千或数百万张图像,那么计算所有这些数百万(或万亿)距离的过程将会非常缓慢。如果你只需要一次比较一个和几千个,我想你已经有两个答案了

但是,如果你真的想找到类似的图像并存储大量(比如数十万)图像,空间数据库使用的R树或其他索引会更好。R-树不是什么神奇的东西,它只是一个专门用于这种多维数据的索引

如果你找不到一个支持这么多维度的空间数据库,我不确定你自己的解决方案将如何创建


一个想法是将9个数字分成3个三胞胎。每个三元组都是一个三维点。因此,每个图像都将存储为三个三维地理点。然后,两幅图像之间的差异将是三个(地理)距离的总和

谷歌上有一个SQL实现。@webarto-事实上,我为SQL Server写了一个。我只是没有把它改写成MySQL。一旦你知道了正确的工具,就有很多选择。就像我的国家所说的,没有工具就没有工匠:)愿意分享你的功能吗?@webarto-非常乐意分享,但在这篇文章中没有意义,因为问题是关于PHP和MySQL的(我不记得遇到过一个关于如何在SQL Server中执行此操作的问题)。如果我在php中执行此过程,我可以分解字符串并进行计算。问题是我需要在SQL查询中执行此操作。此外,我不确定levenshtein是否可以工作,因为这不是图像的感知散列。这些数字的含义是:199与200几乎相同。Levenshteing不同意我感知到的唯一方式在一个查询中可能会非常难看,而且肯定效率很低。在我看来,如果这是9个独立的列,那么这可能是一个合理的查询。是的,这是我的第一个想法,我忘了提到它。它看起来是迄今为止最好的选择。谢谢我刚刚发布的答案。全部在mysql中完成
255,255,255,255,255,255,105,195,305
255,255,255,255,255,255,107,195,304