我需要一个像这里找到的函数: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'。那是关键吗?
答案 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)
此处似乎并不需要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
这是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]。