使用Python和PIL计算两张图像的均方根差
我需要一个像这里找到的那样的函数: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
看起来这里其实不太需要用到 map
和 reduce
。
可以改进一下 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的时候有两个不同的意思,建议把其中一个,或者更好的是两个,都改成更有意义的名字。