How to manually increase Brightness in Pillow np.ndarray

Question:

Im trying to make an Image Editor in Python using tkinter. I’ve developped functions to manipulate images, increasing brightness, contrast and so on. I’ve been getting really wierd results when converting the array back to a Pillow Image using Image.fromarray()

I know there are built in methods to increase brightness, but i’d like to expand this to more complex things. So converting Image to array and the other way arround is so important.

from PIL import Image
import numpy as np

class Imagem:
    def __init__(self, path_imagem):
        self.image = Image.open(path_imagem)

    def brightness(self, factor):
        array_imagem = np.array(self.imagem)
        array_imagem = array_imagem + factor
        self.image = Image.fromarray(array_imagem, mode='RGB')

if __name__ == '__main__':
    img = Imagem('./assets/panda.png')
    img.brightness(30)
    img.image.show()

This is the original Image and the image I’m getting back
original
modified

(These are prints from the images, I couldn’t upload the original images due to size constraints)

shouldn’t I be adding 30 (in this case) to all rgb pixel values?

Answer:

from PIL import Image
import numpy as np

class Imagem:
    def __init__(self, path_imagem):
        self.image = Image.open(path_imagem)

    def brightness(self, factor):
        array_imagem = np.array(self.imagem)
        array_imagem = array_imagem.astype(np.uint16)
        array_imagem = array_imagem + factor
        array_imagem = np.clip(array_imagem, a_min=0, a_max=255)
        self.image = Image.fromarray(array_imagem.astype(np.uint8), mode='RGB')

if __name__ == '__main__':
    img = Imagem('./assets/panda.png')
    img.brightness(30)
    img.image.show()

Thank you for the help 🙂

Asked By: Diogo Lima

||

Answers:

By adding 30, you have overflowed the 0..255 range that can be stored in a uint8. You can see that the brightest areas have burnt out.

You need to promote your data to a larger type, e.g. uint16, and then call np.clip() to clamp the values into the range 0..255 and convert back to uint8 to prevent it.

Also, adding 30 to all RGB channels is not ideal. You will normally get a better result by changing to Lab mode or HSL and just increasing the L channel, else you’ll tend to get colour distortions.

Answered By: Mark Setchell