Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare two images and highlight differences along on the second image

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

like image 908
Sumit Soman Avatar asked May 16 '15 15:05

Sumit Soman


2 Answers

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')
like image 111
jsbueno Avatar answered Nov 04 '22 11:11

jsbueno


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.

like image 24
jcupitt Avatar answered Nov 04 '22 11:11

jcupitt