skip to Main Content

Basically, I’m trying to make a function that will take a given image and a color. for each pixel in the image, it will keep the original alpha value but will change the color to the given one.

for example, if the function gets the arrow image below and the color red,

Original image - all colors

It will output the following image:

Result image - red

In Photoshop and other image editors, this effect called “color overlay”. Is there any quick and easy way of achieving the same result in PIL? Thanks in advance! (;

3

Answers


  1. One way of doing it is to create a solid red image the same size as the original and then copy the alpha channel from the original image across to it:

    from PIL import Image
    
    # Open original image and extract the alpha channel
    im = Image.open('arrow.png')
    alpha = im.getchannel('A')
    
    # Create red image the same size and copy alpha channel across
    red = Image.new('RGBA', im.size, color='red')
    red.putalpha(alpha) 
    

    enter image description here


    Here is a second method using Numpy:

    from PIL import Image
    import numpy as np
    
    # Open image
    im = Image.open('arrow.png')
    
    # Make into Numpy array
    n = np.array(im) 
    
    # Set first three channels to red
    n[...,0:3]=[255,0,0] 
    
    # Convert back to PIL Image and save
    Image.fromarray(n).save('result.png')
    

    A third way is to composite with a similarly-sized red copy and use the original alpha mask:

    from PIL import Image
    
    # Open image
    im = Image.open('arrow.png')                                                                                                       
    
    # Make solid red image same size
    red = Image.new('RGBA', im.size, color='red')                                                                                      
    
    # Composite the two together, honouring the original mask
    im = Image.composite(red,im,im)  
    

    Keywords: Image, image processing, Python, Pillow, PIL, Numpy, extract alpha, alpha channel, transparency, replace transparency, copy transparency, copy alpha, transplant alpha, transplant transparency.

    Login or Signup to reply.
  2. Let us consider the following image – http://www.libpng.org/pub/png/img_png/globe-scene-fish-bowl-pngcrush.png

    image = cv2.imread("/home/thalish/bleed_test/globe-scene-fish-bowl-pngcrush.png",cv2.IMREAD_UNCHANGED)
    
    image[:,:,0],image[:,:,1],image[:,:,2] = (255,0,0) #to replace all pixels with Red but keep alpha channel unchanged
    

    Final Image

    Login or Signup to reply.
  3. Try:

    from PIL import Image
    
    # Takes the input image
    img = Image.open(r"Arrow.png")
    
    # Getting the dimensions of the image
    x, y = img.size
    
    # Obtaining values of Red, Green, Blue for each opaque pixel
    red = int(input("Enter the red value you want in each pixel = "))
    green = int(input("Enter the green value you want in each pixel = "))
    blue = int(input("Enter the blue value you want in each pixel = "))
    
    i = j = 0
    
    # This loop makes sure that alpha only has two discrete values (0 , 255)
    # This is to ensure that constant color is obtained, at pixels where transparence may not be 255
    # (prevents color escapes at pixels where total transparency is not achieved)
    while i < x:
        while j < y:
            r, g, b, a = img.getpixel((i,j))
            if a > 200 and a < 256:
                a = 255
            else:
                a = 0
            img.putpixel((i,j),(r,g,b,a))
            j += 1
        j = 0
        i += 1
    
    i = j = 0
    
    # Two nested loops
    # Outer one goes through rows of image
    # Inner one (nested one) goes through columns of image
    while i < x:
        while j < y:
    
            # This condition checks, if the value of alpha for that individual pixel is 255 (~opaque), 
            # if true then change its RGB values to user defined values
            if img.getpixel((i,j))[-1] == 255:
                img.putpixel((i,j), (red, green, blue, 255))
            j += 1
        j = 0
        i += 1
    
    img.save("Arrow.png")
    

    INPUT:-

    Enter the red value you want in each pixel = 0
    Enter the green value you want in each pixel = 0
    Enter the blue value you want in each pixel = 255
    

    OUTPUT:-

    EXPLANATION FOR THE FIRST LOOP:-

    If the first loop doesn’t flat out, the alpha values by a threshold, then a lot of error gets produced in the output image. i.e. Pixel values near the edge of a object tends to have alpha pixel values a little lesser than 255 (total opacity) to enable smooth anti-aliasing. If these pixels are discarded then output image may look something like this:-

    Notice the unwanted color's in the edge of the arrow

    P.S.:- Even though OpenCV would be the preferred choice for most Image Analysts/Experts, I would definitely advice you to stick with PIL/Pillow at the beginning, as it allows you to get the grasp the fundamentals of imaging in a really friendly way. There is no denying that OpenCV far outweighs PIL in almost every aspect, but still if you learn PIL in the beginning, transitioning from PIL to OpenCV would be alot easier for you to do later on.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search