【问题标题】:How can I compare two NSImages for differences?如何比较两个 NSImage 的差异?
【发布时间】:2011-10-17 20:00:47
【问题描述】:

我正在尝试衡量两个图像之间的百分比差异。

读了很多资料后,我似乎有很多选择,但我不确定最好的方法是什么:

  1. 易于编码
  2. 性能。

我见过的方法有:

非特定语言 - 学术 Image comparison - fast algorithm 和 Mac 特定直接像素访问 http://www.markj.net/iphone-uiimage-pixel-color/

对于以上两种情况和有代码示例来展示如何应用它们,是否有人对哪种解决方案最有意义有任何建议?

【问题讨论】:

  • 你能从图片中得到NSData的实例吗?

标签: objective-c algorithm image macos image-processing


【解决方案1】:

我已经使用此处提到的直方图技术成功计算了两个图像之间的差异。 redmoskito 在您链接到的SO question 中的回答实际上是我的灵感!

以下是我使用的算法的概述:

  1. 将图像转换为灰度 - 比较一个通道而不是三个通道。
  2. 将每个图像划分为n * n“子图像”网格。然后,对于子图像对:
    1. 计算它们的颜色成分直方图。
    2. 计算两个直方图之间的绝对差值。
  3. 两个子图像之间发现的最大差异是衡量两个图像差异的指标。也可以使用其他指标(例如子图像之间的平均差异)。

正如 tkuzzy 在他的回答中指出的那样,如果您的最终目标是二进制“是的,这两个图像(大致)相同”或“不,它们不是”,那么您需要一些有意义的阈值。您可以通过将图像传递给算法并根据其输出以及 您 认为图像的相似程度调整阈值来生成这样的值。我想是machine learning 的一种形式。

我最近就这个主题写了blog post,尽管这是一个更大目标的一部分。我还创建了一个简单的 iPhone 应用程序来演示该算法。您可以在GitHub 上找到源代码;也许会有所帮助?

【讨论】:

    【解决方案2】:

    如果您不告诉我们更多有关图片或变化的信息,就很难提出建议。它们是形状吗?它们是不同的对象吗?您想知道什么类别的对象吗?它们是同一个对象,您想区分对象实例吗?他们是脸吗?他们是指纹吗?物体的姿势相同吗?同一光照下?

    当您说性能时,您的具体意思是什么?图片有多大?总而言之,这真的取决于。如果只是便于编码和性能,我会建议您只找到像素差异的绝对值。这非常容易编码,而且速度也很快,但除了最综合的例子之外,真的不太可能适用于任何其他东西。

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

    【讨论】:

    • 图片为截图。我试图确定图像之间的差异是否不仅仅是时间变化。我不确定最大可能的分辨率是多少,但肯定是 1920 x 1200。
    • @TreeUK 您是否在比较两个预计基本相同的屏幕截图?还是有两个以上的差异可能非常大?
    • 我试图找出的关键是屏幕截图之间的变化是像时间变化这样的小变化还是更大的变化。差异的确切组成 RGB 等与我的目的无关。
    【解决方案3】:

    您可以使用上述小伙子建议的相当基本的减法技术。 @carlosdc 对这种基本技术可用于的图像类型一针见血。我附上了一个示例,您可以自己查看结果。

    第一个显示在某个时间 t 的模拟图像。从第一个图像中减去第二个图像,该图像是在 t + dt 一段时间后拍摄的(模拟)。减去的图像(为清楚起见以黑白形式显示)然后显示模拟在此期间的变化情况。这是如上所述完成的,非常强大且易于编码。

    希望对你有所帮助

    【讨论】:

    • 我真的很想用一些代码来说明这些概念。我没有似乎妨碍我理解的数学背景。
    • 好的。好吧,我将不得不为您挖出一些 FORTRAN 90。这是一段非常基本的代码,但它应该会有所帮助。
    • 谢谢,但我不会说 FORTRAN。
    【解决方案4】:

    这是一些旧的讨厌的 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
    ! =============================================================
    

    希望这有一些用处。一切顺利。

    【讨论】:

    • 谢谢你,你的描述很有帮助,你的 Fortran 代码没有那么多。都一样,谢谢。
    【解决方案5】:

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

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

    1. 计算每张图像的红色、绿色和蓝色直方图
    2. 将每个存储桶之间的差异加起来
    3. 如果差值高于某个阈值,则百分比为 0%
    4. 否则图像中的颜色相似。因此,然后逐个像素进行比较,并将差异转换为百分比。

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

    【讨论】:

    • 谢谢,但是如何计算直方图呢?
    • 这个答案最符合我的问题,尽管它提出了更多问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    相关资源
    最近更新 更多