Contrast can be defined as the spread in the value of brightness, within a specific range, in an image. An image with a high contrast contains a low number of shades or colours, so high contrast isn't always good, like in pictures of people or scenery, for example, as these might have lost informative details. But, this property of images can be helpful if we need to isolate some feature that could be revealed or made clear by increasing the contrast. And, in the opposite case, we could reduce the contrast for making an area more uniform and smooth.
Contrast stretching
P0(x,y) = (P1(x,y) - 100) * 2.0
where P1 is the pixel at (x,y) position in the input image, and P0 is the pixel of the output one. For RGB images, the formula is to apply to all the channels. Note that I chosen 2.0 as the value for the multiplication because it was the value that, to my eyes, returned a better result. I could never stress enough the importance of our personal judgement when we try to get an optimal result.
Here is the code implementing contrast stretching in a greyscale image:
from PIL import Image, ImageTk
import tkinter as tk
def contrast(input_image, value):
if input_image.mode != 'L' and input_image.mode != 'P':
return None
else:
output_image = Image.new('L', (input_image.width,
input_image.height))
for x in range(input_image.width):
for y in range(input_image.height):
pix = input_image.getpixel((x, y))
output_image.putpixel((x,y), int((pix-100) * value))
return output_image
def main():
root = tk.Tk()
img = Image.open("retriver_gray.png", formats=['PNG'])
width = img.width*2+20
height = img.height
root.geometry(f'{width}x{height}')
output_im = contrast(img, 2.0)
if output_im != None:
output_im = ImageTk.PhotoImage(output_im)
input_im = ImageTk.PhotoImage(img)
canvas = tk.Canvas(root, width=width, height=height, bg="#ffffff")
canvas.create_image(width/4-1, height/2-1, image=input_im, state="normal")
canvas.create_image(20+3*img.width/2-1, img.height/2-1, image=output_im, state="normal")
canvas.place(x=0, y=0)
canvas.pack()
root.mainloop()
else:
print("Input image's mode must be 'L' or 'P'"\
"Check https://pillow.readthedocs.io/en/"\
"latest/handbook/concepts.html#concept-modes")
if __name__ == "__main__":
main()
This is the result produced:
The following is a bonus for those of you who came here expecially for the code: contrast stretching for RGB images:
def contrast_rgb(input_image, value):
if input_image.mode == 'L' or input_image.mode == 'P':
output_image = Image.new('L', (input_image.width,
input_image.height))
for x in range(input_image.width):
for y in range(input_image.height):
pix = input_image.getpixel((x, y))
value = value != None and value or 0
output_image.putpixel((x,y), int((pix-100) * value))
elif input_image.mode == 'RGB':
output_image = Image.new('RGB', (input_image.width,
input_image.height))
for x in range(input_image.width):
for y in range(input_image.height):
pix = input_image.getpixel((x, y))
output_image.putpixel((x,y), (int((pix[0]-100) * value),
int((pix[1]-100) * value),
int((pix[2]-100) * value)))
else:
return None
return output_image
The result:
If you enjoy this content and would like to see more of it, or if you wish to know about a specific algorithm, please comment and also share this series. If you haven't read the older posts, head for the first one at this link. or read the next.
No comments:
Post a Comment