【问题标题】:Root mean square difference between two images using Python and PIL使用 Python 和 PIL 的两个图像之间的均方根差
【发布时间】:2011-03-07 02:51:18
【问题描述】:

我需要一个像这里找到的函数:http://effbot.org/zone/pil-comparing-images.htm,它计算两个图像之间的均方根差。代码如下所示:

import ImageChops
import math, operator

def rmsdiff(im1, im2):
    "Calculate the root-mean-square difference between two images"

    h = ImageChops.difference(im1, im2).histogram()

    # calculate rms
    return math.sqrt(reduce(operator.add,
        map(lambda h, i: h*(i**2), h, range(256))
        ) / (float(im1.size[0]) * im1.size[1]))

尝试运行此代码会导致以下错误:TypeError: unsupported operand type(s) for ** or pow(): 'NoneType' and 'int'。有什么问题吗?

【问题讨论】:

    标签: python image-processing


    【解决方案1】:

    考虑使用现有解决方案(例如scikit-image)解决此问题:

    from PIL import Image # No need for ImageChops
    import math
    from skimage import img_as_float
    from skimage.measure import compare_mse as mse
    
    def rmsdiff(im1, im2):
        """Calculates the root mean square error (RSME) between two images"""
        return math.sqrt(mse(img_as_float(im1), img_as_float(im2)))
    

    或者使用NumPy自己写一些简短的东西:

    from PIL import Image, ImageChops
    import math
    import numpy as np
    
    def rmsdiff(im1, im2):
        """Calculates the root mean square error (RSME) between two images"""
        errors = np.asarray(ImageChops.difference(im1, im2)) / 255
        return math.sqrt(np.mean(np.square(errors)))
    

    请注意,这两种方法都将像素强度视为在 [0.0, 1.0] 范围内,而不是 [0, 255]。

    【讨论】:

      【解决方案2】:

      这里似乎不需要mapreduce

      rmsdiff 的改进版本可能是:

      def rmsdiff(im1, im2):
          "Calculate the root-mean-square difference between two images"
          diff = ImageChops.difference(im1, im2)
          h = diff.histogram()
          sq = (value*((idx%256)**2) for idx, value in enumerate(h))
          sum_of_squares = sum(sq)
          rms = math.sqrt(sum_of_squares/float(im1.size[0] * im1.size[1]))
          return rms
      

      这里是source。根据我的测试,Mark Krautheim 提出的改进之所以重要,至少有一个原因:与原始版本相反,当将图像与其自身进行比较时,它会导致返回值为 0.0。

      【讨论】:

        【解决方案3】:

        请看这里https://gist.github.com/bo858585/5377492。 此脚本使用均方根(不划分为 sqrt(3) - 像素是 3 位数 RGB 向量)每对对应 (通过两个比较图像的矩阵 20*20) 像素的位置。脚本总结了像素对之间的这些距离,并将这个总和划分为最大可能的距离——这样脚本就可以得到两个图像的相似度。在比较所有调整为 20*20 的图像之前。您可以改变 MAX_DISTANCE(从 0 到 400),脚本会将或多或少相似的图像归为一组。

        【讨论】:

          【解决方案4】:

          问题在于它创建的直方图没有值(或实际上没有值),而没有相应的像素值。

          即当您找到两个图像的差异时,生成的图像没有任何像素,例如相隔 43 个单位,因此 h[43] = None。

          稍后,您尝试访问范围内每个亮度的像素数 (256),并将其平方,这导致它对 None**2 应该是什么感到困惑。

          考虑将range(256) 更改为h.keys()

          另外,您使用 h 来表示两种不同的事物,请考虑将其中之一的名称更改为有意义的名称,或者更好的是,将两者都更改为有意义的名称。

          【讨论】:

            【解决方案5】:

            在这里猜测一下,但在你的最后一行试试这个,看看它是否有效:

            return math.sqrt(sum(h*(i**2) for i, h in enumerate(h))) / (float(im1.size[0]) * im1.size[1]))
            

            我不确定你为什么会得到你所描述的TypeError,但是如果你使用上面的代码行并继续得到它,那么严重会发生一些奇怪的事情开。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-10-04
              • 2014-06-13
              • 1970-01-01
              • 1970-01-01
              • 2012-04-13
              • 2017-10-13
              相关资源
              最近更新 更多