Php 如何在SQL查询中通过相似性查找图像?
我想处理图像,比如说,在每个区域内建立9个区域,然后找到每个区域的平均颜色,然后将其保存到一个char字段,如下所示: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,
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