使用Python和PIL的两个图像之间的均方差

时间:2010-06-23 01:50:14

标签: python image-processing

我需要一个像这里找到的函数: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:**或pow()的不支持的操作数类型:'NoneType'和'int'。那是关键吗?

5 个答案:

答案 0 :(得分:4)

问题在于它创建了一个没有值(或实际上是无值)的直方图,其中没有相应的像素值。

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

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

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

另外,你使用h来表示两个不同的东西,考虑改变一个的名称,或者更好的是,将两个名称改为有意义的名称。

答案 1 :(得分:2)

在这里疯狂猜测,但在最后一行尝试这个,看看它是否有效:

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

我不确定你为什么会得到你所描述的TypeError,但是如果你使用上面的代码并继续得到它,认真的怪异的东西正在继续。

答案 2 :(得分: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 :(得分:0)

https://gist.github.com/bo858585/5377492。 这个脚本将所有jpg图像从用户目录(指定它)除以它们的相似性,使用均方根(不分为sqrt(3) - 像素是3位RGB矢量),每对相应之间的差异(通过两个比较图像的矩阵20 * 20的像素的位置。脚本总结了像素对之间的这些距离,并将此总和除以最大可能距离 - 这样脚本就可以获得两个图像的相似性。在比较所有调整大小为20 * 20的图像之前。您可以改变MAX_DISTANCE(从0到400),脚本会将更多或更少相似的图像分组到一个组。

答案 4 :(得分:0)

考虑使用现有解决方案解决此问题,例如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]。