MathJax 3

Monday, 19 July 2021

Grey-level image histogram - Pyhton implementation

As promised in the previous post, we will talk about the image's histogram. 


Plotting data obtained from images is helpful to study and understand them. One plot type that can be helpful for any image processing practitioner is the grey-level histogram. The grey-level histogram of an image gives us, as it's easy to deduce, the grey-level distribution of the pixels within the image. 

 

The histogram of an image is the set of numbers M, the value of which representing what percentage of the image is at that grey level. The following formula defines the histogram of an image:

 

hi =  ni/nt   for i = 0  to  (M-1)

 

in which ni is the number of pixels within the image at the ith grey level value and nt is the total number of pixels in the image. 

 

The following function implements a grey-level histogram for a greyscale image:

 

 

def histogram(input_image):
    if input_image.mode != 'L' and input_image.mode != 'P':
        return None
    else:
        IHIST = [0 for i in range(256)]
        HIST = [0 for i in range(256)] ## histogram array
        SUM = 0        
        for x in range(input_image.width):
            for y in range(input_image.height):
                pix = input_image.getpixel((x, y))
                IHIST[pix] = IHIST[pix]+1
                SUM += 1
        for i in range(256):
            HIST[i] = float(IHIST[i]/SUM)
            
        return HIST

 


 

The picture below shows the image and its grey-level histogram:


Histogram interpretation

Histogram interpretation deserves a tutorial of its own, especially if we want to talk also about colour images histogram.
For now, we should understand at least that by examining the histogram of an image is possible to detect some problem caused during its acquisition, as poor or excessive contrast, or a low dynamic range.
We should also be aware of the existence of some techniques involving histograms that can help us to improve our images, as histogram equalization, which we'll discuss in the next post.

The complete code: 

 

from PIL import Image, ImageTk
import tkinter as tk



def histogram(input_image):
    if input_image.mode != 'L' and input_image.mode != 'P':
        return None
    else:
        IHIST = [0 for i in range(256)]
        HIST = [0 for i in range(256)]
        SUM = 0        
        for x in range(input_image.width):
            for y in range(input_image.height):
                pix = input_image.getpixel((x, y))
                IHIST[pix] = IHIST[pix]+1
                SUM += 1
        for i in range(256):
            HIST[i] = float(IHIST[i]/SUM)
            
        return HIST                      

def draw_histogram(canvas, IHIST, hist_w, hist_h):
        ## A bin is a bar of the histogram
        bin_w = round(float(hist_w/512))
        offset = hist_w + 20 ## where we draw the first bin
        for i in range(256):                                                                                                                                                   
            canvas.create_line(bin_w*i+offset, hist_h,
                               bin_w*i+offset, hist_h-IHIST[i])


if __name__=="__main__":
    root = tk.Tk()
    root.title("IMAGE GREY-LEVEL HISTOGRAM")
    img = Image.open("retriver_gray.png")

    width = img.width*2
    height = img.height
    root.geometry(f'{width}x{height}')

    IHIST = histogram(img)
    if IHIST != None:
        hist_w = img.width
        hist_h = img.height

        hist_max = max(IHIST) ## get the max value
        ## Normalize between 0 and hist_h
        for i in range(256):
            IHIST[i] = float(IHIST[i]/hist_max) * hist_h
    
        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")

        draw_histogram(canvas, IHIST, hist_w, hist_h)
             
        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")



No comments:

Post a Comment