Before you begin
- Python 3.12 or newer
- Pillow installed in the same Python environment
Set up your example
- Save the complete code as image-difference.py in a working folder.
- Save the provided sample files in that same folder; run commands from that folder.
- Install Pillow: python -m pip install Pillow
- Generate the original fixtures once: python "make_samples.py". Choose an empty folder so the fixture files do not exist.
Sample files in this download:
- make_samples.py
Download the ZIP, extract it, and open a terminal inside the extracted folder. The source file is image-difference.py.
Run the script
python "image-difference.py" --input "sample.png" --other "second.png" --gain 3 --output "difference.png"If your system uses python3 instead of python, use that command for Python examples. Keep paths containing spaces in quotes. Required inputs and optional settings are described in the code and setup steps.
What to expect
Create a boosted absolute RGB difference image for two equal-size pictures. The added green patch in second.png becomes the visible changed region.
The complete script
#!/usr/bin/env python3
'Visualize pixel differences between images'
import argparse
import json
from pathlib import Path
def write_json(path, value):
data = json.dumps(value, indent=2, ensure_ascii=False, allow_nan=False) + "\n"
with Path(path).open("x", encoding="utf-8", newline="") as handle:
handle.write(data)
import math
try:
from PIL import Image, ImageOps, ImageEnhance, ImageFilter, ImageDraw, ImageFont, ImageChops
except ImportError:
raise SystemExit("Install Pillow first: python -m pip install Pillow")
MAX_PIXELS=20_000_000
def check_size(size):
if min(size)<1 or size[0]*size[1]>MAX_PIXELS:
raise ValueError("Image dimensions must be positive and at most 20 million pixels.")
def read_image(path):
with Image.open(path) as original:
check_size(original.size)
return ImageOps.exif_transpose(original).convert("RGBA")
def save_image(path,image,format="PNG"):
check_size(image.size)
with Path(path).open("xb") as handle:
image.save(handle,format=format)
def main():
parser = argparse.ArgumentParser(description='Visualize pixel differences between images')
parser.add_argument("--input",required=True,help="Local source image")
parser.add_argument("--output",required=True,help="New output file or directory")
parser.add_argument("--other",required=True)
parser.add_argument("--gain",type=float,default=3)
args = parser.parse_args()
if not 1<=args.gain<=10: raise ValueError("Gain must be 1..10.")
a,b=read_image(args.input),read_image(args.other)
if a.size!=b.size: raise ValueError("Images must have equal dimensions.")
def flatten(im):
canvas=Image.new("RGB",im.size,"white")
canvas.paste(im,mask=im.getchannel("A"))
return canvas
difference=ImageChops.difference(flatten(a),flatten(b))
save_image(args.output,ImageEnhance.Brightness(difference).enhance(args.gain))
if __name__ == "__main__":
try:
main()
except (OSError, ValueError, KeyError, TypeError, ArithmeticError, IndexError, LookupError) as exc:
raise SystemExit(str(exc))
Open source as plain text · Download source and sample files
How it works
- Pillow reads the local image; the source is left unchanged and existing destinations are refused.
- Both images are composited onto white first; black output pixels indicate equal visible colors and gain amplifies differences.
- The added green patch in second.png becomes the visible changed region.
Make it your own
--gain
Use --gain 1 for unamplified pixel differences.
Adapt the processing
Edit flatten's white background when comparing images intended for a different matte.
Change one setting at a time, run it again on sample data, and compare the output. The customization guide walks through this process.
If something goes wrong
The images have different sizes.
Align and resize them first; this tool does not register images or compare semantic similarity.
The destination already exists.
Choose a new --output path. The script deliberately refuses to replace an existing result.
Reference & next steps
These official references explain the underlying tools. The Scriptage example and guide are original instructional content. See verification notes for what has been checked and the limits of those checks.
Copies a template for your own notes. It does not send anything.