pythonnumpyopencvimage-processingroi

Histogram of a region of an image


I want to get the histogrm of a region in a numpy image in python. I found a solution on how to use a mask here.

this solution didnt help me because if i use it I will loose the real number of black pixels. Also, the region that i want to get is not necessarly rectangular.


Solution

  • To compute histogram use np.histogram function. It returns a histogram and bins. So you can store the results and work with it:

    hist, bins = np.histogram(arr, bins=bins, range=range)
    

    If you want to plot the results, you can use plt.bar after applying np.histogramsimply passing bins and hist:

    plt.bar(bins, hist)
    

    Another option is using matplotlib plt.hist it computes the histogram and plots it from a raw data:

    plt.hist(arr, bins=bins)
    

    Here is the complete example for the histogram of image region of any shape:

    Code:

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.misc import face
    from PIL import Image, ImageDraw
    
    # Let's create test image with different colors
    img = np.zeros((300, 300, 3), dtype=np.uint8)
    img[0:150, 0:150] = [255, 0, 0]
    img[0:150, 150:] = [0, 255, 0]
    img[150:, :150] = [0, 0, 255]
    img[150:, 150:] = [255, 255, 255]
    
    # define our function for preparing mask
    def prepare_mask(polygon, image):
        """Returns binary mask based on input polygon presented as list of coordinates of vertices
        Params:
            polygon (list) - coordinates of polygon's vertices. Ex: [(x1,y1),(x2,y2),...] or [x1,y1,x2,y2,...]
            image (numpy array) - original image. Will be used to create mask of the same size. Shape (H, W, C).
        Output:
            mask (numpy array) - boolean mask. Shape (H, W).
        """
        # create an "empty" pre-mask with the same size as original image
        width = image.shape[1]
        height = image.shape[0]
        mask = Image.new('L', (width, height), 0)
        # Draw your mask based on polygon
        ImageDraw.Draw(mask).polygon(polygon, outline=1, fill=1)
        # Covert to np array
        mask = np.array(mask).astype(bool)
        return mask
    
    
    def compute_histogram(mask, image):
        """Returns histogram for image region defined by mask for each channel
        Params:
            image (numpy array) - original image. Shape (H, W, C).
            mask (numpy array) - boolean mask. Shape (H, W).
        Output:
            list of tuples, each tuple (each channel) contains 2 arrays: first - computed histogram, the second - bins.
    
        """
        # Apply binary mask to your array, you will get array with shape (N, C)
        region = image[mask]
    
        red = np.histogram(region[..., 0].ravel(), bins=256, range=[0, 256])
        green = np.histogram(region[..., 1].ravel(), bins=256, range=[0, 256])
        blue = np.histogram(region[..., 2].ravel(), bins=256, range=[0, 256])
    
        return [red, green, blue]
    
    
    def plot_histogram(histograms):
        """Plots histogram computed for each channel.
        Params:
            histogram (list of tuples) - [(red_ch_hist, bins), (green_ch_hist, bins), (green_ch_hist, bins)]
        """
    
        colors = ['r', 'g', 'b']
        for hist, ch in zip(histograms, colors):
            plt.bar(hist[1][:256], hist[0], color=ch)
    
    # Create some test masks
    red_polygon = [(50, 100), (50, 50), (100, 75)]
    green_polygon = [(200, 100), (200, 50), (250, 75)]
    blue_polygon = [(50, 250), (50, 200), (100, 225)]
    white_polygon = [(200, 250), (200, 200), (250, 225)]
    polygons = [red_polygon, green_polygon, blue_polygon, white_polygon]
    
    for polygon in polygons:
        mask = prepare_mask(polygon, img)
        histograms = compute_histogram(mask, img)
    
        # Let's plot our test results
        plt.figure(figsize=(10, 10))
    
        plt.subplot(221)
        plt.imshow(img)
        plt.title('Image')
    
        plt.subplot(222)
        plt.imshow(mask, cmap='gray')
        plt.title('Mask')
    
    
        plt.subplot(223)
        plot_histogram(histograms)
        plt.title('Histogram')
    
        plt.show()
    

    Output:

    enter image description here enter image description here enter image description here enter image description here

    The final test on raccoon:

    Code:

    raccoon = face()
    polygon = [(200, 700), (150, 600), (300, 500), (300, 400), (400, 500)]
    mask = prepare_mask(polygon, raccoon)
    histograms = compute_histogram(mask, raccoon)
    
    plt.figure(figsize=(10, 10))
    
    plt.subplot(221)
    plt.imshow(raccoon)
    plt.title('Image')
    
    plt.subplot(222)
    plt.imshow(mask, cmap='gray')
    plt.title('Mask')
    
    
    plt.subplot(223)
    plot_histogram(histograms)
    plt.title('Histogram')
    
    plt.show()
    

    Output:

    enter image description here