比较2个一位图像的相似性

时间:2016-03-21 16:43:59

标签: image algorithm

我正在尝试将源图像与集合中的数千个图像进行比较,以获得最可能匹配的相似度得分(0-1)。每个图像都很小(64x64或更小)。每个图像都是1位,这意味着每个像素都是关闭(完全透明)或开启(完全白色)。我正在尝试创建一个非常快速的相似性算法来比较这些图像。我通过谷歌搜索发现了许多相似度算法,但它们都涉及比较大型全彩色图像,我不需要这样做。

我意识到我只能比较匹配/不匹配的像素,但考虑到比较集可能非常大,这可能会很慢。比较集图像将与查找图像的大小完全相同。

是否可以为这些类型的图像创建哈希或其他快速查找,其中可以执行哈希或二进制搜索查找并使用最可能的匹配创建相似性得分?

5 个答案:

答案 0 :(得分:4)

要获得二进制图像的比较分数,我建议您使用xor运算计算Hamming distance,然后计算1的数量。使用SSSE3指令的快速popcount操作可以大大加快。

汉明距离告诉你两个二进制字符串之间不同的位数(因此它实际上是一个相异度值)。要获得范围内的分数,例如[0, 1],您可以除以图像的大小(这样您就可以获得图像大小不变的分数)。

关于与数千张图片的比较,确保它是一个瓶颈,因为如果数据不是那么大,它可能比你想象的要快。如果你仍然需要加快速度,你可以考虑这些想法中的任何一个或两个:

1)并行化:例如,该函数可能很容易与OpenMP或tbb并行化。 2)哈希表:使用每个图像的第一个(或某些子集)位在矢量中对它们进行索引。然后,比较那些只属于同一个哈希箱的图像。当然,这是一种近似方法,你不会得到任何一对图像的比较分数,只有那些足够相似的图像。

请记住,如果要与所有图像进行比较,则必须对所有数据库进行完全比较,因此除了并行化之外几乎没有机会加快速度。

答案 1 :(得分:1)

执行此操作的一种方法是二叉树。每个图像的像素可以转换为1和0的字符串。然后该字符串可用于构造二叉树。

在检查新字符串时,你只需要开始关注路径所在的位置,如果你到达一个叶子节点,那么它就存在了,如果你没有那么它是新的。

上图显示了使用3个长度为4的字符串构建的树

1010
0110
0001

因此,如果再次出现0001,只需按照路径行进,如果您最终进入一个叶子(实心圆圈),那么字符串(图像)就会重复并再次出现。如果没有,那么你也可以添加它,同时知道它是新的和独特的。

每次比较和添加都需要0(n)次,其中n是字符串的长度。在您的情况下n == 32*32

答案 2 :(得分:1)

如果您的图像以类似位图的格式存储像素数据,则每行只是32位整数值,您可以简单地比较图像行

for iy = 0 to ImageHeight - 1 do
  if   CastToInt32(Image1.Scanline[0]) <> CastToInt32(Image2.Scanline[0]) then 
     break due to inequality
//32 comparisons or less

对于近似相似性的情况,您可以计算所有行的xor-ed值中计算设置位的差异总数。

NumberOf1Bits(Value1 xor Value2)

P.S。 Delphi中的直接实现每个图像/图像比较需要300纳秒(对于100万个图像为0.3秒)。单线程,i5处理器,不匹配限制450。 低失配限制的时间将明显减少(限制45为47 ns)。 主要时间吃 - NumberOf1Bits / popcount功能。

答案 3 :(得分:1)

您可以实现四叉树结构https://en.wikipedia.org/wiki/Quadtree

递归分割图像。在每个级别,存储1和/或0像素的数量(一个可以从另一个计算)

Ex:对于这张图片:

0 1 1 0

0 1 0 1

0 0 0 0

0 0 1 0

您计算以下树:

(5)

(2) - (2) - (0) - (1)

(0) - (1) - (0) - (1) - - - (1) - (0) - (0) - (1) - - - (0) - (0) - (0) - (0) - - - (0) - (0) - (1) - (0)

树的较高级别是较粗略的图像版本:

第一级:

5/16

第二级:

2/4 2/4

0/4 1/4

然后,您的相似性得分可能是计算0和1的数量是否不同,在不同的递归水平,每个级别的权重。你可以得到它的近似值(快速消除非常不同的图像),而不是沿着整棵树走下去。

答案 4 :(得分:1)

如果您发现完全比较所有图像(使用例如ChronoTrigger的答案)仍然需要花费太多时间,请考虑这两种策略以减少必要的比较次数。

我会假设图像是逐行比较的。首先完全比较第一张图像,将其得分存储为最大值,然后移至下一张图像,每次根据需要更新最大值。在逐行比较每个图像时,在每行之后(或每n行之后)执行以下操作:

  1. 到目前为止,检查到目前为止匹配位不匹配的数量是否超过了具有最高分数的图像中的不匹配数。如果是,则此图像永远不会达到最高分,并且可以将其丢弃。
  2. 如果到目前为止每行的平均得分低于具有最高得分的图像的每行平均得分,请在下次运行期间继续比较,并跳到下一张图像。
  3. 重复此操作,直到所有图像都被完全检查或丢弃。

    在基于示例图像的100个随机32x32像素图像上尝试此策略,每个图像随机位数改变,给出了这个有希望的结果:

    FIRST RUN (100 images):
    images checked completely:             5    (maximum score: 1015, image #52)
    postponed after 1 line:               59
    discarded after 1 line:               35
    discarded after 10 lines:              1
    
    SECOND RUN (59 images):
    discarded without additional checks:  31    (because of new maximum score)
    discarded after 1 additional line:    12
    discarded after 2 additional lines:    9
    discarded after 3 additional lines:    1
    discarded after 4 additional lines:    3
    discarded after 5 additional lines:    1
    discarded after 6 additional lines:    2
    
    Total number of lines compared:      326 out of 3200 lines (~ 10.1875 out of 100 images)