Python OpenCV直方图均衡化详解
作者:盼小辉丶
前言
图像处理技术是计算机视觉项目的核心,通常是计算机视觉项目中的关键工具,可以使用它们来完成各种计算机视觉任务。在本文中,将介绍如何使用 OpenCV
函数 cv2.equalizeHist()
执行直方图均衡,并将其应用于灰度和彩色图像,cv2.equalizeHist()
函数将亮度归一化并提高图像的对比度。
灰度直方图均衡化
使用 cv2.equalizeHist()
函数来均衡给定灰度图像的对比度:
# 加载图像并转换为灰度图像 image = cv2.imread('example.png') gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) hist = cv2.calcHist([gray_image], [0], None, [256], [0, 256]) # 直方图均衡化 gray_image_eq = cv2.equalizeHist(gray_image) # 直方图均衡化后的图像直方图 hist_eq = cv2.calcHist([gray_image_eq], [0], None, [256], [0, 256])
为了深入了解直方图均衡,我们对原始灰度图像进行修改,为图像的每个像素添加/减去 30,并计算直方图均衡前后的直方图:
M = np.ones(gray_image.shape, dtype='uint8') * 30 # 为图像的每个像素添加 30 added_image = cv2.add(gray_image, M) hist_added_image = cv2.calcHist([added_image], [0], None, [256], [0, 256]) # 直方图均衡化 added_image_eq = cv2.equalizeHist(gray_image_eq) hist_eq_added_image = cv2.calcHist([added_image_eq], [0], None, [256], [0, 256]) # 为图像的每个像素减去 30 subtracted_image = cv2.subtract(gray_image, M) hist_subtracted_image = cv2.calcHist([subtracted_image], [0], None, [256], [0, 256]) # 直方图均衡化 subtracted_image_eq = cv2.equalizeHist(subtracted_image) hist_eq_subtracted_image = cv2.calcHist([subtracted_image_eq], [0], None, [256], [0, 256])
最后,绘制所有这些图像:
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) # 可视化 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') # 其他图像的可视化方法类似,不再赘述 # ...
程序运行的输出如下图所示:
在上图中,我们可以看到三个均衡化后的图像非常相似,这也反映在均衡化后的直方图中,这是因为直方图均衡化倾向于标准化图像的亮度,同时增加对比度。
颜色直方图均衡化
使用相同的方法,我们可以在彩色图像中执行直方图均衡,将直方图均衡应用于 BGR 图像的每个通道(虽然这不是彩色图像直方图均衡的最佳方法),创建 equalize_hist_color()
函数,使用 cv2.split()
分割 BGR
图像并将 cv2.equalizeHist()
函数应用于每个通道,最后,使用 cv2.merge()
合并结果通道:
def equalize_hist_color(img): # 使用 cv2.split() 分割 BGR 图像 channels = cv2.split(img) eq_channels = [] # 将 cv2.equalizeHist() 函数应用于每个通道 for ch in channels: eq_channels.append(cv2.equalizeHist(ch)) # 使用 cv2.merge() 合并所有结果通道 eq_image = cv2.merge(eq_channels) return eq_image
接下来,将此函数应用于三个不同的图像:原始 BGR 图像、将原始图像的每个像素值添加 10、将原始图像的每个像素值减去 10,并计算直方图均衡前后的直方图:
# 加载图像 image = cv2.imread('example.png') # 计算直方图均衡前后的直方图 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 # 为图像的每个像素添加 10 added_image = cv2.add(image, M) # 直方图均衡前后的直方图 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) # 为图像的每个像素减去 10 subtracted_image = cv2.subtract(image, M) # 直方图均衡前后的直方图 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)
最后,绘制所有这些图像:
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) # 可视化 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']) # 其他图像的可视化方法类似,不再赘述 # ...
将直方图均衡化应用于 BGR
图像的每个通道并不是颜色直方图均衡化的好方法,这是由于 BGR
色彩空间的加性特性导致彩色图像的颜色变化很大。由于我们独立地改变三个通道中的亮度和对比度,因此在合并均衡通道时,这可能会导致图像中出现新的色调,正如上图所看到的那样。
一种颜色直方图均衡化更好的方法是将 BGR 图像转换为包含亮度/强度通道的色彩空间( Yuv
、Lab
、HSV
和 HSL
)。然后,只在亮度通道上应用直方图均衡,最后合并通道并将它们转换回 BGR
颜色空间,以 HSV
空间为例,创建 equalize_hist_color_hsv()
函数实现上述颜色直方图归一化方法:
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
接下来,将此函数应用于三个不同的图像:原始 BGR 图像、将原始图像的每个像素值添加 10、将原始图像的每个像素值减去 10,并计算直方图均衡前后的直方图:
hist_color = hist_color_img(image) # 计算直方图均衡前后的直方图 image_eq = equalize_hist_color_hsv(image) hist_image_eq = hist_color_img(image_eq) M = np.ones(image.shape, dtype="uint8") * 10 # 为图像的每个像素添加 10 added_image = cv2.add(image, M) hist_color_added_image = hist_color_img(added_image) # 直方图均衡前后的直方图 added_image_eq = equalize_hist_color_hsv(added_image) hist_added_image_eq = hist_color_img(added_image_eq) # 为图像的每个像素减去 10 subtracted_image = cv2.subtract(image, M) hist_color_subtracted_image = hist_color_img(subtracted_image) # 直方图均衡前后的直方图 subtracted_image_eq = equalize_hist_color_hsv(subtracted_image) hist_subtracted_image_eq = hist_color_img(subtracted_image_eq)
最后,绘制所有这些图像:
# show_img_with_matplotlib() 和 show_hist_with_matplotlib_rgb() 函数与上一示例相同 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']) # 其他图像的可视化方法类似,不再赘述 # ...
由上图可以看出,仅均衡 HSV
图像的 V
通道得到的结果比均衡 BGR
图像的所有通道的效果要好很多,也可以将这种方法用于其他包含亮度/强度通道的色彩空间( Yuv
、Lab
和 HSL
)。
以上就是Python OpenCV直方图均衡化详解的详细内容,更多关于OpenCV直方图均衡化的资料请关注脚本之家其它相关文章!