Color Image Histograms

In our earlier post, we talked about how the histogram of a black and white picture enabled us to understand the pixel intensity distribution. Furthermore, by equalizing its’ histogram we were able to improve the image’s contrast. Undoubtedly the question is, by examining color image histograms, can we do the same? Different from before, as we will have 3-4 channels in a color image, we need to adapt our approach slightly.

Getting Ready

In order to improve the contrast of a color image, we need to first plot the histogram of a color image. Similar to before, we will import OpenCV and our helper function to display images in Jupyter lab.

import cv2
import numpy as np

#The line below is necessary to show Matplotlib's plots inside a Jupyter Notebook
%matplotlib inline

from matplotlib import pyplot as plt

#Use this helper function if you are working in Jupyter Lab
#If not, then directly use cv2.imshow(<window name>, <image>)

def showimage(myimage, figsize=[10,10]):
    if (myimage.ndim>2):  #This only applies to RGB or RGBA images (e.g. not to Black and White images)
        myimage = myimage[:,:,::-1] #OpenCV follows BGR order, while matplotlib likely follows RGB order
        
    fig, ax = plt.subplots(figsize=figsize)
    ax.imshow(myimage, cmap = 'gray', interpolation = 'bicubic')
    plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
    plt.show()

Subsequently, we read in our color image.

colorimage = cv2.imread("Hwy7McCowan Night.jpg")
showimage(colorimage)
Original image for generating color image histograms

Color Image Histograms – How to

Rather than having only a single channel to process, color images can have 3-4 channels. As a result we need to slightly adjust the approach we took on greyscale images. In order to plot the histogram, we will create histograms for each channel and combine them onto a single plot.

color = ('b','g','r')

#Loop through each color sequentially
for i,col in enumerate(color):
    
    #To use OpenCV's calcHist function, uncomment below
    #histr = cv2.calcHist([colorimage],[i],None,[256],[0,256])
    
    #To use numpy histogram function, uncomment below
    histr, _ = np.histogram(colorimage[:,:,i],256,[0,256])

    plt.plot(histr,color = col)  #Add histogram to our plot 
    plt.xlim([0,256])
    
plt.show()  #Show our plot
Resulting color image histogram

Equalising a Color Image Histogram

Once we have our color image histogram, we next attempt to equalize each channel. As a result, we hope to achieve a wider distribution and thereby enhance contrast. Since OpenCV’s equalizeHist function only works with a single channel at a time, we quickly apply this function as below.

# For ease of understanding, we explicitly equalize each channel individually
colorimage_b = cv2.equalizeHist(colorimage[:,:,0])
colorimage_g = cv2.equalizeHist(colorimage[:,:,1])
colorimage_r = cv2.equalizeHist(colorimage[:,:,2])

# Next we stack our equalized channels back into a single image
colorimage_e = np.stack((colorimage_b,colorimage_g,colorimage_r), axis=2)
colorimage_e.shape
(540, 960, 3)

As shown above, after we equalize each channel, we use Numpy’s stack function to combine them back into our image. In order to verify this was successful, we quickly check the shape of our array.

All that remains now, is to quickly plot our new histogram to see what happens after equalization. Finally, we can display the new and old image to verify the results.

# Using Numpy to calculate the histogram
color = ('b','g','r')
for i,col in enumerate(color):
    histr, _ = np.histogram(colorimage_e[:,:,i],256,[0,256])
    plt.plot(histr,color = col)
    plt.xlim([0,256])
plt.show()
Histogram equalization applied on original image
# Using Numpy's function to append the two images horizontally
side_by_side = np.hstack((colorimage,colorimage_e))
showimage(side_by_side,[20,10])
Side by side comparison of results

Results

Generally, as we compare the old and new image, without doubt we managed to improve the image’s contrast. For instance, notice how the blue bus on the lower right has more distinct border around its’ doors and windows. Additionally, the grass field on the lower left also exhibits more details and texture. These are desired and welcomed results after improving contrast.

Conversely, this approach is not without pitfall. Upon further examination, notice how areas in our original picture that had good contrast now experiences over exposure. For example, the mall on the upper right, or the long queue of cars on the upper left. In essence, we’ve lost certain clarity or information from the image. Finally, notice how the colors didn’t come well together on the upper left. Here we start to see parts of the lawn showing shades of red that weren’t in the original picture.

Even though we’ve managed to improve the contrast of a colored image, it is not without its down sides. Perhaps there is a better way…

FreedomvcAbout Alan Wong
Alan is a part time Digital enthusiast and full time innovator who believes in freedom for all via Digital Transformation. 
兼職人工智能愛好者,全職企業家利用數碼科技釋放潛能與自由。

LinkedIn

Leave a Reply