使用Python和PIL计算两张图像的均方根差

6 投票
5 回答
19433 浏览
提问于 2025-04-16 00:19

我需要一个像这里找到的那样的函数: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'。这是什么问题呢?

5 个回答

2

这是个大胆的猜测,不过你可以试试在最后一行加上这个,看能不能解决问题:

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

我不太确定你为什么会遇到你说的那个TypeError错误,但如果你用了上面的代码还是出现这个错误,那就说明有些事情真的很奇怪。

3

看起来这里其实不太需要用到 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

这里是 源代码。根据我的测试,Mark Krautheim 提出的改进很重要,至少有一个原因就是:跟原来的版本相比,当比较一张图片和它自己时,返回值会是 0.0。

5

问题在于,它生成了一个直方图,但在没有对应像素值的地方,直方图的值是空的(或者说是None)。

也就是说,当你在比较两张图片的差异时,结果图片中没有像素值相差43的情况,所以h[43]的值就是None。

之后,你尝试访问每个亮度值在0到255之间的像素数量,并对这个数量进行平方运算,这就导致了它对None的平方该是什么感到困惑。

可以考虑把range(256)改成h.keys()

另外,你在使用h的时候有两个不同的意思,建议把其中一个,或者更好的是两个,都改成更有意义的名字。

撰写回答