“This is the 18th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

preface

Image processing technology is the core of computer vision project, usually is the key tool in computer vision project, can be used to complete a variety of computer vision tasks. In this article, you will learn how to use the OpenCV function cv2.equalizehist () to perform histogram equalization and apply it to grayscale and color images. The cv2.equalizehist () function normalizes brightness and improves image contrast.

Gray histogram equalization

Use the cv2.equalizehist () function to balance the contrast of a given grayscale image:

# Load the image and convert it to grayscale image
image = cv2.imread('example.png')
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([gray_image], [0].None[256], [0.256])
# Histogram equalization
gray_image_eq = cv2.equalizeHist(gray_image)
Histogram histogram after equalization
hist_eq = cv2.calcHist([gray_image_eq], [0].None[256], [0.256])
Copy the code

In order to have a deeper understanding of histogram equalization, we modify the original gray image, add/subtract 30 for each pixel of the image, and calculate the histogram before and after histogram equalization:

M = np.ones(gray_image.shape, dtype='uint8') * 30
Add 30 to each pixel of the image
added_image = cv2.add(gray_image, M)
hist_added_image = cv2.calcHist([added_image], [0].None[256], [0.256])
# Histogram equalization
added_image_eq = cv2.equalizeHist(gray_image_eq)
hist_eq_added_image = cv2.calcHist([added_image_eq], [0].None[256], [0.256])
Subtract 30 from each pixel of the image
subtracted_image = cv2.subtract(gray_image, M)
hist_subtracted_image = cv2.calcHist([subtracted_image], [0].None[256], [0.256])
# Histogram equalization
subtracted_image_eq = cv2.equalizeHist(subtracted_image)
hist_eq_subtracted_image = cv2.calcHist([subtracted_image_eq], [0].None[256], [0.256])
Copy the code

Finally, draw all these images:

def show_img_with_matplotlib(color_img, title, pos) :
    img_RGB = color_img[:, :, ::-1]
    ax = plt.subplot(3.4, pos)
    plt.imshow(img_RGB)
    plt.title(title, fontsize=8)
    plt.axis('off')

def show_hist_with_matplotlib_gray(hist, title, pos, color) :
    ax = plt.subplot(3.4, pos)
    plt.xlabel("bins")
    plt.ylabel("number of pixels")
    plt.xlim([0.256])
    plt.plot(hist, color=color)
# visualization
show_img_with_matplotlib(cv2.cvtColor(gray_image, cv2.COLOR_GRAY2BGR), "gray".1)
show_hist_with_matplotlib_gray(hist, "grayscale histogram".2.'m')
show_img_with_matplotlib(cv2.cvtColor(added_image, cv2.COLOR_GRAY2BGR), "gray lighter".5)
show_hist_with_matplotlib_gray(hist_added_image, "grayscale histogram".6.'m')
show_img_with_matplotlib(cv2.cvtColor(subtracted_image, cv2.COLOR_GRAY2BGR), "gray darker".9)
show_hist_with_matplotlib_gray(hist_subtracted_image, "grayscale histogram".10.'m')
# The visualization methods of other images are similar and will not be repeated
#...
Copy the code

The output of the program is shown below:

In the figure above, we can see that the three equalized images are very similar, which is also reflected in the equalized histogram, because histogram equalization tends to standardize the brightness of the image while increasing the contrast.

Color histogram equalization

Using the same method, we can perform histogram equalization in color images, apply histogram equalization to each channel of the BGR image (although this is not the best method for color image histogram equalization), create the equalize_HIST_color () function, Split the BGR image using cv2.split() and apply the cv2.equalizehist () function to each channel. Finally, merge the result channel using cv2.merge() :

def equalize_hist_color(img) :
    # Split the BGR image using cv2.split()
    channels = cv2.split(img)
    eq_channels = []
    Apply the cv2.equalizehist () function to each channel
    for ch in channels:
        eq_channels.append(cv2.equalizeHist(ch))
    Merge all result channels using cv2.merge()
    eq_image = cv2.merge(eq_channels)
    return eq_image
Copy the code

Next, apply this function to three different images: the original BGR image, add 10 to each pixel value of the original image, subtract 10 from each pixel value of the original image, and calculate the histogram before and after histogram equalization:

# load image
image = cv2.imread('example.png')
# Calculate the histogram before and after histogram equalization
hist_color = hist_color_img(image)
image_eq = equalize_hist_color(image)
hist_image_eq = hist_color_img(image_eq)

M = np.ones(image.shape, dtype="uint8") * 10
Add 10 to each pixel of the image
added_image = cv2.add(image, M)
Histogram before and after equalization
hist_color_added_image = hist_color_img(added_image)
added_image_eq = equalize_hist_color(added_image)
hist_added_image_eq = hist_color_img(added_image_eq)
Subtract 10 from each pixel of the image
subtracted_image = cv2.subtract(image, M)
Histogram before and after equalization
hist_color_subtracted_image = hist_color_img(subtracted_image)
subtracted_image_eq = equalize_hist_color(subtracted_image)
hist_subtracted_image_eq = hist_color_img(subtracted_image_eq)
Copy the code

Finally, draw all these images:

def show_img_with_matplotlib(color_img, title, pos) :
    img_RGB = color_img[:, :, ::-1]
    ax = plt.subplot(3.4, pos)
    plt.imshow(img_RGB)
    plt.title(title, fontsize=8)
    plt.axis('off')

def show_hist_with_matplotlib_rgb(hist, title, pos, color) :
    ax = plt.subplot(3.4, pos)
    plt.xlabel("bins")
    plt.ylabel("number of pixels")
    plt.xlim([0.256])
    for (h, c) in zip(hist, color):
        plt.plot(h, color=c)
# visualization
show_img_with_matplotlib(image, "image".1)
show_hist_with_matplotlib_rgb(hist_color, "color histogram".2['b'.'g'.'r'])
show_img_with_matplotlib(added_image, "image lighter".5)
show_hist_with_matplotlib_rgb(hist_color_added_image, "color histogram".6['b'.'g'.'r'])
show_img_with_matplotlib(subtracted_image, "image darker".9)
show_hist_with_matplotlib_rgb(hist_color_subtracted_image, "color histogram".10['b'.'g'.'r'])
# The visualization methods of other images are similar and will not be repeated
#...
Copy the code

Applying histogram equalization to each channel of BGR image is not a good method for color histogram equalization, because the color of BGR image varies greatly due to the additive property of color space. Since we change the brightness and contrast in the three channels independently, this can result in new hues in the image when merging equalization channels, as seen in the image above.

A better method of color histogram equalization is to convert the BGR image into a color space containing brightness/intensity channels (Yuv, Lab, HSV, and HSL). Then, only apply histogram equalization on brightness channels, and finally merge channels and convert them back to BGR color space. Taking HSV space as an example, create equalize_HIST_COLOR_HSV () function to achieve the above color histogram normalization method:

def equalize_hist_color_hsv(img) :
    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
Copy the code

Next, apply this function to three different images: the original BGR image, add 10 to each pixel value of the original image, subtract 10 from each pixel value of the original image, and calculate the histogram before and after histogram equalization:

hist_color = hist_color_img(image)
# Calculate the histogram before and after histogram equalization
image_eq = equalize_hist_color_hsv(image)
hist_image_eq = hist_color_img(image_eq)

M = np.ones(image.shape, dtype="uint8") * 10
Add 10 to each pixel of the image
added_image = cv2.add(image, M)
hist_color_added_image = hist_color_img(added_image)
Histogram before and after equalization
added_image_eq = equalize_hist_color_hsv(added_image)
hist_added_image_eq = hist_color_img(added_image_eq)
Subtract 10 from each pixel of the image
subtracted_image = cv2.subtract(image, M)
hist_color_subtracted_image = hist_color_img(subtracted_image)
Histogram before and after equalization
subtracted_image_eq = equalize_hist_color_hsv(subtracted_image)
hist_subtracted_image_eq = hist_color_img(subtracted_image_eq)
Copy the code

Finally, draw all these images:

The # show_img_with_matplotlib() and show_HIST_with_matplotlib_rgb () functions are the same as in the previous example
show_img_with_matplotlib(image, "image".1)
show_hist_with_matplotlib_rgb(hist_color, "color histogram".2['b'.'g'.'r'])
show_img_with_matplotlib(added_image, "image lighter".5)
show_hist_with_matplotlib_rgb(hist_color_added_image, "color histogram".6['b'.'g'.'r'])
# The visualization methods of other images are similar and will not be repeated
#...
Copy the code

As can be seen from the figure above, the result of equalizing only the V channel of HSV image is much better than that of equalizing all channels of BGR image. This method can also be applied to other color Spaces containing brightness/intensity channels (Yuv, Lab and HSL).

A link to the

Basic concept of OpenCV histogram

OpenCV gray histogram details

OpenCV color histogram with custom histogram visualization