Search code examples
pythonimage-processingpython-imaging-library

Python PIL overlay pixels with color while mantaining the lightness and shadows


I had two scripts which I merged but 2 problems arised:

  1. for light colors which are overlayed the result is way too bright as it overlays the original pixels that were brighter than others with total white rather than their color. For example "lightblue" "pink" and "grey". While the rest of the colors when overlayed the result is perfect

  2. it won't process the png which first word is "2white" (3rd condition).

It seems like the color is getting overlayed just like the "Linear Dodge" blend mode in Photoshop, while what I want would be a "Overlay" blend mode.

I'd be very thankful if someone could help me one with this.

Here's the results for example:

original image

blue overlay

lightblue overlay

Photo 4 and 5 would be the wanted result for lightblue and blue overlay.

wanted result lightblue ball

wanted result blue ball


Solution

  • Did you know that there's a Python package blend-modes to implement blend modes? I didn't, until I went searching. Since you edited the question to say you wanted the equivalent of Photoshop's Overlay mode, this became easy.

    import blend_modes
    import numpy as np
    from PIL import Image
    
    def overlay(im, color):
        ''' Takes a PIL.Image and RGB tuple as input,
            returns a PIL.Image of the result.
        '''
        im2 = np.array(im).astype(float)
        im3 = im2.copy()
        color_with_alpha = list(color) + [255] * (im3.shape[2]-len(color))
        color_array = np.array(color_with_alpha, dtype=float)
        im3[:,:] = color_array
        blended_img_float = blend_modes.overlay(im2, im3, 1.0)
        blended_img = np.uint8(blended_img_float)
        return Image.fromarray(blended_img)
    

    And here's the result with your sample image and lightblue (99, 168, 231):

    enter image description here