1

我从图像中获取 25 个样本,获取它们的平均 rgb 值并将它们保存在 5x5 颜色数组中。这些是我的“签名”。签名中的值如下所示:

Color signature[5][5];

-21233 -1 -323211 ... ...
-123 -12323 ...  
...

我可以从签名的索引中获得红色、蓝色和绿色值。我使用这些值来比较两个图像的签名并获得“差异”值。

signature[1][1].getBlue() = 123, Color[1][1].getRed() = 200 ..

for (int x = 0; x < 5; x++) {   
        for (int y = 0;y < 5; y++) {
            int r1 = signature[x][y].getRed();
            int g1 = signature[x][y].getGreen();
            int b1 = signature[x][y].getBlue();
            int r2 = signature2[x][y].getRed();
            int g2 = signature2[x][y].getGreen();
            int b2 = signature2[x][y].getBlue();
            double tempDiff =  Math.sqrt((r1 - r2) * (r1 - r2) 
                                       + (g1 - g2) * (g1 - g2) 
                                       + (b1 - b2) * (b1 - b2));
            difference += tempDiff;
        }
 }

我还获得了图像的第二个签名,显示了它们边缘找到的版本的签名。比较两张图像,我将正常特征差异与边缘特征差异相乘,得到最终的差异值。

在比较两张图像时,一切都很好。但是,我得到了很多图像,所以我将签名保存在数据库中,如下所示:

Table images:
-COLUMN name-       -COLUMN signature-             -COLUMN edge signature-
myimg.jpg  |-12312 -132 -2 ... (25 of them) |-123 -1 -1234 -6921 .. (25 of them)|

我只是将签名索引与它们之间的空格连接起来并保存为字符串。

这是我的问题:我需要找到一张图片的相似之处。如果我从数据库中选择所有图像,事情会变得非常缓慢并且我的内存不足。我可以从数据库中选择 1000 张图像,比较并获取下 1000 张,但这甚至更慢。

我需要一种方法来比较查询中的图像签名,我准备好更改我的表的列,甚至准备尝试具有 100 列包含签名的所有 RGB 值的疯狂表。我需要减少或散列签名。您可以建议任何方法/方法、链接或库吗?任何帮助,将不胜感激。

如果需要,我在 NetBeans 上使用 Java,与 MySQL 一起工作。

4

3 回答 3

0

散列很可能不起作用,因为您正在搜索相似而不是相同的图像。即使您将相似的图像映射到同一个键,它也不会起作用,因为“相似”关系不是基于您对比较函数的定义的传递(A 类似于 B,B 类似于 C,但 C 可能不类似于 A )。

我唯一能想到的就是像你说的那样存储在 25 * 3 列中。您可以编写 SQL 语句以仅选择可能通过距离测试的图像(如果差异已经大于阈值,则将其过滤掉)。如果数据库中的图像不太相似,则此方法应该可以正常工作。但是,如果数据库中的图像彼此非常相似,则此方法很糟糕。

于 2012-05-29T08:37:12.943 回答
0

您可以使用 SQL 来执行此操作。

如果您想查找所有重复项,您可以使用类似这样的内容(替换正确的字段名称)

SELECT i.[name] FROM images i 
  INNER JOIN 
     (SELECT signature, edge_signature 
          FROM images
           GROUP BY signature, edge_signature
            HAVING COUNT(*) > 1 ) dups
   on i.signature = dups.signature and i.edge_signature = dups.edge_signature;

如果要查找特定图像的重复项,请创建签名并将它们放入此 SQL

SELECT i.[name]
  FROM images
    WHERE signature = '$yourCalculatedSignaturehere'
    and edge_signature = '$yourCalculatedEdgeSignaturehere';

这两个查询都可能返回多行(如果没有重复,则返回 0 行)。

您可以使用索引来加速这些查询signature, edge_signature, [name] (该索引可能会使您的表使用的磁盘空间增加一倍,但它应该会显着提高查询的性能)。

于 2012-05-29T08:45:58.913 回答
0

在看到我们需要 150 列之后,想到了两种方法:

  1. 根据逻辑减少列数。
  2. 使用感知散列(散列,其中接近的散列值表示接近的散列前值)

然而,在一个丑陋而混乱的实现之后,代码运行得很好。我所做的只是使用 SQL 查询在问题中进行计算,并从数据库中获取最相似的 50 张图片。得到结果后,我稍微整理了一下代码,它运行良好且快速。

因此,我们认为没有真正需要实施上述方法,因为它们会降低发现相似性的成功率,而且我们不需要更快。我们得到了最好的 50 个结果,因此内存复杂性也不是问题。

对于所有在项目中的“Java 部分”(或任何其他“代码”部分)中存在速度或内存问题的人,我强烈建议将尽可能多的工作转移到“数据库部分”并通过查询完成工作.

于 2012-07-02T07:55:59.510 回答