Compare two images and highlight differences along on the second image
Solution 1
PIL does have some handy image manipulation methods, but also a lot of shortcomings when one wants to start doing serious image processing -
Most Python lterature will recomend you to switch to use NumPy over your pixel data, wich will give you full control - Other imaging libraries such as leptonica, gegl and vips all have Python bindings and a range of nice function for image composition/segmentation.
In this case, the thing is to imagine how one would get to the desired output in an image manipulation program: You'd have a black (or other color) shade to place over the original image, and over this, paste the second image, but using a threshold (i.e. a pixel either is equal or is different - all intermediate values should be rounded to "different) of the differences as a mask to the second image.
I modified your function to create such a composition -
from PIL import Image, ImageChops, ImageDraw
point_table = ([0] + ([255] * 255))
def new_gray(size, color):
img = Image.new('L',size)
dr = ImageDraw.Draw(img)
dr.rectangle((0,0) + size, color)
return img
def black_or_b(a, b, opacity=0.85):
diff = ImageChops.difference(a, b)
diff = diff.convert('L')
# Hack: there is no threshold in PILL,
# so we add the difference with itself to do
# a poor man's thresholding of the mask:
#(the values for equal pixels- 0 - don't add up)
thresholded_diff = diff
for repeat in range(3):
thresholded_diff = ImageChops.add(thresholded_diff, thresholded_diff)
h,w = size = diff.size
mask = new_gray(size, int(255 * (opacity)))
shade = new_gray(size, 0)
new = a.copy()
new.paste(shade, mask=mask)
# To have the original image show partially
# on the final result, simply put "diff" instead of thresholded_diff bellow
new.paste(b, mask=thresholded_diff)
return new
a = Image.open('a.png')
b = Image.open('b.png')
c = black_or_b(a, b)
c.save('c.png')
Solution 2
Here's a solution using libvips:
import sys
from gi.repository import Vips
a = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL)
b = Vips.Image.new_from_file(sys.argv[2], access = Vips.Access.SEQUENTIAL)
# a != b makes an N-band image with 0/255 for false/true ... we have to OR the
# bands together to get a 1-band mask image which is true for pixels which
# differ in any band
mask = (a != b).bandbool("or")
# now pick pixels from a or b with the mask ... dim false pixels down
diff = mask.ifthenelse(a, b * 0.2)
diff.write_to_file(sys.argv[3])
With PNG images, most CPU time is spent in PNG read and write, so vips is only a bit faster than the PIL solution.
libvips does use a lot less memory, especially for large images. libvips is a streaming library: it can load, process and save the result all at the same time, it does not need to have the whole image loaded into memory before it can start work.
For a 10,000 x 10,000 RGB tif, libvips is about twice as fast and needs about 1/10th the memory.
Related videos on Youtube
Sumit Soman
Updated on September 16, 2022Comments
-
Sumit Soman over 1 year
Below is the current working code in python using PIL for highlighting the difference between the two images. But rest of the images is blacken.
Currently i want to show the background as well along with the highlighted image.
Is there anyway i can keep the show the background lighter and just highlight the differences.
from PIL import Image, ImageChops point_table = ([0] + ([255] * 255)) def black_or_b(a, b): diff = ImageChops.difference(a, b) diff = diff.convert('L') # diff = diff.point(point_table) h,w=diff.size new = diff.convert('RGB') new.paste(b, mask=diff) return new a = Image.open('i1.png') b = Image.open('i2.png') c = black_or_b(a, b) c.save('diff.png')
!https://drive.google.com/file/d/0BylgVQ7RN4ZhTUtUU1hmc1FUVlE/view?usp=sharing
-
jsbueno almost 9 yearsOh well - the expected custom around here is to click on "accept" for the answer, rather than sending cheers! :-) Thanks anyway.
-
jsbueno almost 9 yearsBTW, for one needing this for just a couple images, and don't wanting to fidle with Python installs - I answered how to the samething interactivelly using GIMP here: graphicdesign.stackexchange.com/questions/27484/…