简体   繁体   中英

Root mean square difference between two images using Python and PIL

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.

ie 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.

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.

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.

See here https://gist.github.com/bo858585/5377492 . This script divides all jpg images from user directory (specify it) to groups by their similarity using root-mean-square (without dividing to sqrt(3) - pixel is 3-number RGB vector) of the difference between each pair of corresponding (by position at matrix 20*20) pixels of two comparing images. Script summarize these distances between pairs of pixels and divide this sum into maximum possible distance - this way script gets the procent of similarity of two images. Before comparing all images resized to 20*20. You may vary MAX_DISTANCE (from 0 to 400) and script will group more or less similar images to one group.

Consider solving this using an existing solution such as 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)))

Alternatively write something short yourself using 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)))

Note that both methods treat pixel intensity as in the range [0.0, 1.0] instead of [0, 255].

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM