如何比较两个NSImages的差异?

4
我正在尝试衡量两张图片之间的百分比差异。经过大量阅读,我似乎有几个选择,但我不确定最好的方法是什么,因为需要考虑以下两点:
1. 编码的易用性 2. 性能
我看到的方法有:
1. 非特定语言 - 学术图像比较 - 快速算法和Mac特定的直接像素访问http://www.markj.net/iphone-uiimage-pixel-color/ 请问有没有人有关于上述两种情况最合理的解决方案的建议,并且有代码示例来展示如何应用它们?

你能从图片中获取一个 NSData 实例吗? - aopsfan
5个回答

4
我使用这里提到的直方图技术成功地计算了两个图像之间的差异。你链接的SO问题中redmoskito的回答实际上是我的灵感来源!
以下是我使用的算法概述:
1. 将图像转换为灰度图像-仅比较一个通道而不是三个。 2. 将每个图像分成“子图像”的n * n网格。然后,对于子图像对:
a. 计算它们的颜色组合直方图。 b. 计算两个直方图之间的绝对差异。
3. 在两个子图像之间找到的最大差异是两个图像之间差异的一种度量。也可以使用其他指标(例如子图像之间的平均差异)。
如tskuzzy在他的回答中所指出的,如果您的最终目标是二进制的“是,这两个图像(大致)相同”或“不,它们不同”,则需要一些有意义的阈值。您可以通过将图像传入算法并根据其输出和您认为图像的相似程度来调整阈值来产生这样的值。我想这是一种机器学习的形式。
最近我写了一篇博客文章,探讨了这个话题,尽管这只是一个更大目标的一部分。我还创建了一个简单的iPhone应用程序来演示该算法。您可以在GitHub上找到源代码;也许它会有所帮助?

2
您可以使用上面的小伙子建议的基本减法技术。@carlosdc关于此基本技术可用于哪种类型的图像给出了正确的指导意见。我附上了一个示例,您可以自己查看结果。
第一张图片显示了某个时间t模拟中的图像。从第一张图片中减去了第二张图片,第二张图片是在稍后的一段时间(模拟)t+dt拍摄的。扣掉的图像(为了清晰起见为黑白)然后显示了模拟在该时间内的变化。如上所述,这样做非常有力和易于编码。
希望这能在某种程度上对您有所帮助。 来自蟹状星云模拟同步辐射的图像 109天后拍摄的从另一张图片中扣去的图像

我真的需要一些代码来说明这些概念。我没有数学背景,这似乎妨碍了我的理解。 - Tristan Warner-Smith
好的,我得为您找一下FORTRAN 90。这是一段相当基础的代码,但应该会有所帮助。 - MoonKnight
谢谢,但我不会说FORTRAN。 - Tristan Warner-Smith

2

如果您没有更多关于图像或变化的信息,建议是非常困难的。它们是形状吗?它们是不同的对象,你想知道什么类的对象吗?它们是相同的对象,您想区分对象实例吗?它们是脸部吗?它们是指纹吗?这些对象处于相同的姿势下吗?在相同的光照下?

当您说性能时,您确切地指的是什么?这些图像有多大?总的来说,这取决于具体情况。根据您所说的,如果只是为了编码和性能方便,我建议只查找像素差的绝对值。这很容易编写,并且速度快,但真的只适用于最合成的示例。

话虽如此,我想向您指出:DHOG、GLOH、SURF 和 SIFT。


这些图片是屏幕截图。我正在尝试确定这些图片之间的差异是否仅仅是时间变化。我不确定最大可能的分辨率是多少,但肯定不会超过1920 x 1200。 - Tristan Warner-Smith
@TreeUK 你是在比较两个预期基本相同的屏幕截图吗?还是有超过两个可能存在非常大的差异? - SSteve
我试图找出的关键是屏幕截图之间的变化是否只是像时间改变这样的小变化,还是更大的变化。对于我的目的来说,差异的确切组成RGB等是无关紧要的。 - Tristan Warner-Smith

2

这是一些老旧的、难以理解的FORTRAN代码,但它应该可以给您提供基本思路。实际上并不难。由于我正在使用双色调板,您需要为R、G和B分别执行此操作。也就是说,计算每个单元格/像素中的强度或值,并将其存储在某个数组中。对于另一个图像也要执行相同的操作,然后将其中一个数组从另一个数组中减去,这将留下一些色彩丰富的差值图像。我的建议是按照上面的建议,计算R、G和B分量的总和的大小,这样您就只会得到一个值。将其写入数组,对于另一个图像也要执行相同的操作,然后相减。然后为R、G或B创建一个新范围,并将结果减去的数组映射到此范围内,这将使结果更加清晰。

* =============================================================
      SUBROUTINE SUBTRACT(FNAME1,FNAME2,IOS)
*     This routine writes a model to files
* =============================================================
*    Common :
      INCLUDE 'CONST.CMN'
      INCLUDE 'IO.CMN'
      INCLUDE 'SYNCH.CMN'
      INCLUDE 'PGP.CMN'
*    Input :
      CHARACTER fname1*(sznam),fname2*(sznam)
*    Output :
      integer IOS
*    Variables:
       logical glue
       character fullname*(szlin)
       character dir*(szlin),ftype*(3)
       integer i,j,nxy1,nxy2
       real si1(2*maxc,2*maxc),si2(2*maxc,2*maxc)
* =================================================================

       IOS = 1
       nomap=.true.

       ftype='map'
       dir='./pictures'

!    reading first image
       if(.not.glue(dir,fname2,ftype,fullname))then
           write(*,31) fullname
           return
       endif

       OPEN(unit2,status='old',name=fullname,form='unformatted',err=10,iostat=ios)

       read(unit2,err=11)nxy2
       read(unit2,err=11)rad,dxy
       do i=1,nxy2
          do j=1,nxy2
             read(unit2,err=11)si2(i,j)
          enddo
       enddo

       CLOSE(unit2)


!    reading second image
       if(.not.glue(dir,fname1,ftype,fullname))then
           write(*,31) fullname
           return
       endif

       OPEN(unit2,status='old',name=fullname,form='unformatted',err=10,iostat=ios)

       read(unit2,err=11)nxy1
       read(unit2,err=11)rad,dxy
       do i=1,nxy1
          do j=1,nxy1
             read(unit2,err=11)si1(i,j)
          enddo
       enddo

       CLOSE(unit2)

!    substracting images 
       if(nxy1.eq.nxy2)then 
           nxy=nxy1
           do i=1,nxy1
              do j=1,nxy1
                 si(i,j)=si2(i,j)-si1(i,j)
              enddo
           enddo
       else
          print *,'SUBSTRACT: Different sizes of image arrays'
          IOS=0 
          return
       endif

*  normal finishing
       IOS=0 
       nomap=.false.
       return

*  exceptional finishing
10     write (*,30) fullname
       return
11     write (*,32) fullname
       return

30     format('Cannot open file   ',72A)
31     format('Improper filename   ',72A)
32     format('Error reading from file   ',72A)

      end
! =============================================================

希望这对您有所帮助。祝一切顺利。

2
谢谢你,你的描述非常有帮助,但是你的Fortran代码就不那么好了。不过还是谢谢。 - Tristan Warner-Smith

1

在你提供的第一个链接中,直方图比较方法是编码最简单、速度最快的方法。然而,关键点匹配将提供更准确的结果,因为您想知道描述两个图像之间差异的精确数字。

要实现直方图方法,我会执行以下操作:

  1. 计算每个图像的红色、绿色和蓝色直方图
  2. 将每个桶之间的差异相加
  3. 如果差异超过一定阈值,则百分比为0%
  4. 否则,在图像中找到的颜色是相似的。然后进行逐像素比较,并将差异转换为百分比。

我不知道任何精确的算法来查找图像的关键点。但是,一旦您为每个图像找到它们,就可以针对每个关键点进行逐像素比较。


谢谢,但是如何计算直方图? - Tristan Warner-Smith
这个答案最贴近我的问题,尽管它也引发了更多的问题。 - Tristan Warner-Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接