Following the same approach, we can perform histogram equalization in color images. We have to say this is not the best approach for histogram equalization in color images and we will see how to perform it correctly. Therefore, this first (and incorrect) version applies histogram equalization to each channel of the BGR images. This approach can be seen in the following code:
def equalize_hist_color(img):
"""Equalize the image splitting the image applying cv2.equalizeHist() to each channel and merging the results"""
channels = cv2.split(img)
eq_channels = []
for ch in channels:
eq_channels.append(cv2.equalizeHist(ch))
eq_image = cv2.merge(eq_channels)
return eq_image
We have created the equalize_hist_color() function, which splits the BGR image by using cv2.split() and applies the cv2.equalizeHist() function to each channel. Finally, we merge all the resulting channels using cv2.merge(). We have applied this function to three different images. The first one is the original BGR image. The second one is the original image but modified in the sense that we have added 15 to every pixel of the image. The third one is the original image but modified in the sense that we have subtracted 15 from every pixel of the image. We have also calculated histograms before and after the equalization of the histogram.
Finally, all of these images are plotted. The output of the color_histogram_equalization.py script can be seen in the following screenshot:
We have commented that equalizing the three channels is not a good approach because the color shade changes dramatically. This is due to the additive properties of the BGR color space. As we are changing both the brightness and the contrast in the three channels independently, this can lead to new color shades appearing in the image when merging the equalized channels. This issue can be seen in the previous screenshot.
A better approach is to convert the BGR image to a color space containing a luminance/intensity channel (Yuv, Lab, HSV, and HSL). Then, we apply histogram equalization only on the luminance channel and, finally, perform inverse transformation, that is, we merge the channels and convert them back to the BGR color space.
This approach can be seen in the color_histogram_equalization_hsv.py script, where the equalize_hist_color_hsv() function will perform this functionality:
def equalize_hist_color_hsv(img):
"""Equalize the image splitting the image after HSV conversion and applying cv2.equalizeHist()
to the V channel, merging the channels and convert back to the BGR color space
"""
H, S, V = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV))
eq_V = cv2.equalizeHist(V)
eq_image = cv2.cvtColor(cv2.merge([H, S, eq_V]), cv2.COLOR_HSV2BGR)
return eq_image
The output can be seen in the following screenshot:
As can be seen, obtained the results obtained after equalizing only the V channel of the HSV image are much better than equalizing all the channels of the BGR image. As we commented, this approach is also valid for a color space containing a luminance/intensity channel (Yuv, Lab, HSV, and HSL). This will be seen in the next section.