Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
Return the % difference of two given images.
Only works with images of the same file type and color channels.
from __future__ import print_function
from PIL import Image, ImageChops, ImageStat
DIFF_IMG_FILE = "diff_img.png"
def diff(
im1_file, im2_file, delete_diff_file=False, diff_img_file=None, ignore_alpha=False
Calculate the difference between two images by comparing channel values at the pixel
level. If the images are different sizes, the second will be resized to match the
`delete_diff_file`: removes the diff image after ratio found
`diff_img_file`: filename to store diff image
`ignore_alpha`: ignore the alpha channel for ratio calculation, and set the diff
image's alpha to fully opaque
if not diff_img_file:
diff_img_file = DIFF_IMG_FILE
im1 =
im2 =
# Ensure we have the same color channels (RGBA vs RGB)
if im1.mode != im2.mode:
raise ValueError(
"Differing color modes:\n {}: {}\n {}: {}\n"
"Ensure image color modes are the same."
).format(im1_file, im1.mode, im2_file, im2.mode)
# Coerce 2nd dimensions to same as 1st
im2 = im2.resize((im1.width, im1.height))
# Generate diff image in memory.
diff_img = ImageChops.difference(im1, im2)
if ignore_alpha:
if not delete_diff_file:
if "." not in diff_img_file:
extension = "png"
extension = diff_img_file.split(".")[-1]
if extension in ("jpg", "jpeg"):
# For some reason, save() thinks "jpg" is invalid
# This doesn't affect the image's saved filename
extension = "jpeg"
diff_img = diff_img.convert("RGB"), extension)
# Calculate difference as a ratio.
stat = ImageStat.Stat(diff_img)
# stat.mean can be [r,g,b] or [r,g,b,a].
removed_channels = 1 if ignore_alpha and len(stat.mean) == 4 else 0
num_channels = len(stat.mean) - removed_channels
sum_channel_values = sum(stat.mean[:num_channels])
max_all_channels = num_channels * 255
diff_ratio = sum_channel_values / max_all_channels
return diff_ratio