I need to have a function like the one found here: http://effbot.org/zone/pil-comparing-images.htm that calculates the root mean square difference between two images. The code looks like this:
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]))
Trying to run this code leads to the following error: TypeError: unsupported operand type(s) for ** or pow(): 'NoneType' and 'int'. That's the matter with it?
The problem is that it is creating a histogram that has no values (or really None values) where there is no corresponding pixel value.
i.e. when you are finding the diff of the two images, the resulting image doesn't have any pixels that are, say, 43 units apart, so h[43] = None.
Later, you try to access the number of pixels at each brightness in the range(256), and square it, which is causing it to get confused about what None**2 should be.
Consider changing range(256)
to h.keys()
.
Also, you are using h to mean two different things, consider changing the name of one or, better still, both of them to meaningful names.
It seems that map
and reduce
are not really needed here.
An improved version of rmsdiff
could be:
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
Here is the source. The improvement suggested by Mark Krautheim is important for at least one reason according to my tests: contrary to the original version, it leads to a return value of 0.0 when comparing an image with itself.
Wild guess here, but try this in your last line and see if it works:
return math.sqrt(sum(h*(i**2) for i, h in enumerate(h))) / (float(im1.size[0]) * im1.size[1]))
I'm not sure offhand why you'd get the TypeError
you're describing, but if you use the above line of code and continue to get it, something seriously weird is going on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With