Search code examples
pythonpython-imaging-library

How to overlay two images in python?


I try to overlay two images but the result is not what I want. imag1 is a dermocopy image occluded with hair. image a hair-free image. I substract them to get the hair. When i try to reverse the operation by summimg imag1 and image 2, the result is different. the hair looks white while it is black.

from PIL import Image, ImageChops

# Load the images
image1 = Image.open('C:/Users/asus/Desktop/Testing/hairoccluded/ISIC_0024327.jpg')
image2 = Image.open('C:/Users/asus/Desktop/Testing/hairfree/ISIC_0024327.jpg')

# Subtract image2 from image1
subtracted_image = ImageChops.subtract(image2, image1)

# Reverse the subtraction using ImageChops.add
reversed_image = ImageChops.add(image2, subtracted_image)

# Display the reversed image
reversed_image.show()

[[[enter image description here](https://ienter image description herestack.imgur.com/bzo4m.jpg)](https://i.sstatic.net/n0XAO.jpg)](https://i.sstatic.net/akeor.jpg)

THe opeation image.add should be reversed correctly


Solution

  • There are two issues:

    • The math is incorrect:

    subtracted_image = ImageChops.subtract(image2, image1)
    ==> subtracted_image = image2 - image1

    reversed_image = ImageChops.add(image2, subtracted_image)
    ==> reversed_image = image2 + subtracted_image
    ==> reversed_image = image2 + (image2 - image1)
    ==> reversed_image = image2*2 - image1

    As you can see the math is wrong.
    The correct statement is:
    reversed_image = ImageChops.add(image1, subtracted_image)
    ==> reversed_image = image1 + (image2 - image1)
    ==> reversed_image = image2


    • The second issue is that ImageChops.subtract and ImageChops.add are not reversible operations.
      That is because the data type is uint8, and can't have negative values (and can't have values above 255).
      When using ImageChops.subtract, all negative values are clipped to zero.
      When using ImageChops.add, all values above 255 are clipped to 255.
      The clipping to range [0, 255] loses data, and we are not getting the original image.

    There is a nice explanation in the following post.


    We may use ImageChops.subtract_modulo and ImageChops.add_modulo, which are reversible.
    The math is not intuitive, but it's working:

    from PIL import Image, ImageChops
    
    # Load the images
    image1 = Image.open('image1.jpg')
    image2 = Image.open('image2.jpg')
    
    # Subtract image2 from image1
    subtracted_image = ImageChops.subtract_modulo(image1, image2)  # image1 - image2
    
    reversed_image = ImageChops.add_modulo(image2, subtracted_image)  # image2 + (image1 - image2)
    
    # Display the reversed image
    reversed_image.show() 
    

    More intuitive solution is converting the images to NumPy arrays with type dtype np.int32 or np.int16.
    Then subtract and add the NumPy arrays.
    The advantage is that np.int32 or np.int16 types may hold positive and negative values, and have a larger range that avoids arithmetic overflow.