一,简介
在上一篇文章中,我们探讨了直方图的基本概念,并详细讲解了如何利用OpenCV来查看图像直方图,以及如何实现直方图均衡化。在此基础上,本篇将继续深入,介绍直方图均衡化的高级应用,包括直方图匹配、局部直方图均衡化以及彩色图像的直方图均衡化技术。
二、直方图匹配
直方图均衡化能自动增强图像的整体对比度,但是往往结果难以受到控制。实际中常常需要增强某个特定灰度值范围内的对比度或使图像灰度值的分布满足特定需求这个时候就需要直方图匹配技术。
直方图匹配,亦称作直方图规定化,是一种旨在调整图像灰度分布的图像处理技术,目的是使其与指定参考图像的直方图相吻合。此技术有助于提升图像的视觉效果,尤其在需要特定灰度分布以凸显图像特征时尤为有效。直方图匹配的执行步骤包括:
- 参考图像直方图计算:选取一个参考图像,并计算其直方图。
- 累积分布函数(CDF)计算:计算参考图像直方图的累积分布函数。
- 目标图像直方图与CDF计算:对目标图像执行相同的操作,获取其直方图和CDF。
- 映射关系建立:通过比较目标图像与参考图像的CDF,建立灰度级之间的映射关系,通常通过查
找目标图像CDF值在参考图像CDF中的对应灰度级来实现。 - 映射应用:依据建立的映射关系,将目标图像的每个像素值重新映射到新的灰度级。
- 生成匹配后的图像:应用映射后的灰度值,创建出具有参考图像直方图特征的新图像。
直方图匹配的应用领域包括:
图像风格转换:使一幅图像在视觉上更接近另一幅图像的风格。
图像增强:在特定应用场景中,通过匹配特定直方图来增强图像的特定特征。
图像复原:在图像复原过程中,利用直方图匹配调整灰度分布,以改善复原效果。
注意事项:
直方图匹配过程主要是改变目标图像的灰度分布,使其与参考图像的直方图相似,但这种改变并不涉及图像的实际内容,如形状、纹理或场景结构等。因此,尽管目标图像的灰度分布(即像素的亮度级别)会发生变化,图像中的物体、形状、颜色等视觉内容可能并不会与参考图像保持一致。换句话说,直方图匹配可能会改变图像的整体外观,但不会改变图像中对象的具体识别信息或场景的实质性内容,并且匹配过程可能会引入噪声或失真,因此需根据实际情况进行适当调整。
使用代码:
# 1.60 彩色图像的直方图匹配
import cv2
import numpy as np
# 读取并调整图像大小到640x480
img = cv2.resize(cv2.imread("sky1.jpg", flags=1),(640,480)) # flags=1 表示以彩色图像格式读取
imgRef = cv2.resize(cv2.imread("sky2.jpg", flags=1),(640,480)) # 读取并调整参考图像的大小,用于直方图匹配
# 获取图像的通道数
_, _, channel = img.shape
# 初始化输出图像,其大小和类型与原始图像相同
imgOut = np.zeros_like(img)
# 遍历每个通道
for i in range(channel):
# 计算原始图像在当前通道的直方图,并返回直方图数组和每个箱子的边界
histImg, _ = np.histogram(img[:, :, i], 256)
# 计算参考图像在当前通道的直方图
histRef, _ = np.histogram(imgRef[:, :, i], 256)
# 计算原始图像的累积分布函数 (CDF)
cdfImg = np.cumsum(histImg)
# 计算参考图像的累积分布函数 (CDF)
cdfRef = np.cumsum(histRef)
# 对每个灰度级进行遍历
for j in range(256):
# 计算当前灰度级的CDF值与参考图像CDF值的差值的绝对值
tmp = abs(cdfImg[j] - cdfRef)
# 将numpy数组转换为列表
tmp = tmp.tolist()
# 找到差值最小的索引,即最接近的灰度级
index = tmp.index(min(tmp))
# 将原始图像中对应灰度级的像素值替换为匹配后的灰度级
imgOut[:, :, i][img[:, :, i] == j] = index
# 显示原始图像
cv2.imshow("img", img)
# 显示参考图像
cv2.imshow("imgRef", imgRef)
# 显示直方图匹配后的图像
cv2.imshow("imgOut", imgOut)
# 等待按键后关闭所有窗口
cv2.waitKey(0)
效果:
可以实现类似图像风格迁移的效果,但速度较慢,可用来扩充数据集或者批量P图
三、局部直方图均衡化
局部直方图均衡化(Local Histogram Equalization)是一种针对传统直方图均衡化方法的改进,其目的是避免传统方法可能导致的局部对比度降低的问题。传统直方图均衡化会对整个图像的灰度分布进行全局调整,以实现灰度级的均匀分布,但这有时会牺牲图像中特定区域的对比度。相比之下,局部直方图均衡化通过在图像的不同区域实施差异化的均衡化策略,旨在保留这些区域的局部细节和对比度。
局部直方图均衡化的实施过程包括以下几个步骤:
- 图像分割:将输入图像划分为若干个小的区域,这些区域通常被称为块或窗口。
- 局部直方图计算:对每个小区域单独计算其局部直方图,以反映该区域的灰度分布特性。
- 局部累积分布函数(CDF)计算:对每个局部直方图计算累积分布函数,以获得每个灰度级在该区域中的分布情况。
- 局部映射关系建立:根据每个区域的CDF建立相应的灰度级映射关系,这些映射关系反映了均衡化后的灰度级分布。
- 局部映射应用:将每个小区域的像素值按照其CDF映射到新的灰度级,从而实现局部均衡化。
- 合成匹配后的图像:将所有小区域的均衡化结果合并,得到最终的均衡化图像。
局部直方图均衡化的优势在于:
- 保留局部对比度:通过局部处理,可以保留图像中的局部对比度,避免全局均衡化可能导致的细节丢失。
- 适应性:该方法能够更好地适应图像中不同区域的照明变化和对比度差异
注意:
在实施局部直方图均衡化时,选择合适的块大小对于取得理想效果至关重要。如果块大小设置过小,可能会丢失图像中的细节信息;相反,如果块过大,可能会引入额外的噪声。因此,确定一个既能保留必要细节又能有效抑制噪声的块大小是关键。
此外,由于局部直方图均衡化需要对每个小区域分别计算直方图和累积分布函数,这相对于全局直方图均衡化来说,计算效率可能会较低。全局均衡化只需要对整个图像进行一次直方图和CDF的计算,而局部均衡化则需要重复这个过程对每个区域进行处理。尽管如此,局部均衡化在保持图像局部对比度和适应图像局部特征方面具有显著优势,因此在需要精细调整图像对比度和细节保留的场景中,它仍然是首选的方法。
在opencv中有一个实现局部直方图均衡化的方法cv2.createCLAHE(clipLimit, tileGridSize)函数说明:
参数说明:
clipLimit 参数定义了一个对比度增强的阈值。当直方图中某个灰度级的对比度增强超过这个阈值时,该灰度级的对比度增强会被限制在 clipLimit 以下。。
tileGridSize: 这是一个整数元组,表示将图像分割成的小块的大小。例如,(8, 8) 表示将图像分割成 8x8 的块。每个小块的直方图将被单独计算和均衡化,然后将结果合并以形成最终的均衡化图像。
使用代码:
# 1.60 彩色图像的直方图匹配
import cv2
import numpy as np
path = r"E:\PS\2.png"
img = cv2.imread(path, 0)
equ1 = cv2.equalizeHist(img) # 普通的直方图均衡化
clahe = cv2.createCLAHE(8, (8, 8)) # 局部直方图均衡化,创建clahe对象
equ2 = clahe.apply(img) # 将clahe对象应用到img上,返回增强图片
cv2.imshow("equ1", equ1)
cv2.imshow("equ2", equ2)
cv2.waitKey(0)
效果:
左侧普通直方图均衡化,右侧局部直方图均衡化
四、彩色直方图均衡化
彩色直方图均衡化(Color Histogram Equalization)是一种针对彩色图像的直方图均衡化技术。与灰度图像的直方图均衡化类似,彩色直方图均衡化的目的是通过调整图像的像素分布,使得输出图像的直方图尽可能平坦,从而增强图像的全局对比度。然而,彩色直方图均衡化是在彩色图像的每个颜色通道上分别进行,而不是在整个图像上进行。
彩色直方图均衡化的实现步骤:
- 颜色分离:将彩色图像分离成三个或更多颜色通道(红、绿、蓝等)。
- 计算每个通道的直方图:对每个颜色通道分别计算直方图。
- 计算累积分布函数(CDF):对每个通道的直方图计算累积分布函数。
- 计算直方图均衡化映射:将每个通道的累积分布函数值乘以通道的最大灰度级,得到每个通道的新映射值。
- 应用映射:根据映射关系,将每个通道的像素值映射到新的灰度级。
- 合成匹配后的图像:将所有通道的映射结果合并成最终的匹配图像
在进行彩色直方图均衡化时,需要注意以下几点:首先,选择合适的颜色空间对于实现理想的图像处理效果至关重要,常见的选择包括RGB和HSV等。其次,由于需要对每个颜色通道单独计算直方图和累积分布函数,因此其计算效率可能不如全局直方图均衡化。尽管如此,彩色直方图均衡化仍是一种有用的工具,可以在保持图像颜色信息的同时提高对比度,从而实现更好的视觉效果。
本文将介绍两种实现彩色直方图均衡化的方法。
4.1 rgb彩色直方图均衡化
将图像rgb三色通道拆分,分开进行直方图均衡化,并将处理后的三通道灰度图按照通道维度拼接起来,获得新的三通道图像
实现代码:
# 1.60 彩色图像的直方图匹配
import cv2
import numpy as np
path = r"E:\PS\2.png"
img = cv2.imread(path)
(b, g, r) = cv2.split(img) # 通道拆分
bH = cv2.equalizeHist(b) # b通道直方图均衡化
gH = cv2.equalizeHist(g) # g通道直方图均衡化
rH = cv2.equalizeHist(r) # r通道直方图均衡化
result = cv2.merge((bH, gH, rH)) # 通道合并
cv2.imshow("result", result)
cv2.waitKey(0)
效果:
原图
处理后的图片:
图像亮度提升但部分颜色失真
4.2 ycrb 彩色直方图均衡化
YCbCr(Y’CbCr)是一种用于表示彩色图像中的颜色信息的色彩空间,它根据ITU-R BT.601标准定义,主要用于视频传输和显示。YCbCr色彩空间包括三个分量:Y’(亮度分量),它是一个灰度值,与颜色无关,通常用于彩色视频的亮度信号;Cb(蓝色色差分量),表示蓝色信号与Y’分量之间的差值,包含了蓝色分量的信息;Cr(红色色差分量),表示红色信号与Y’分量之间的差值,包含了红色分量的信息。通过Y’、Cb和Cr三个分量的组合,YCbCr色彩空间能够准确地表示彩色图像中的颜色信息,并在视频处理和显示中发挥重要作用。要对图像进行彩色直方图均衡化,首先先将图像转化到ycrb颜色空间,然后对其中的y通道(亮度通道)做局部直方图均衡化(crcb颜色通道最好不要动,颜色容易变)这样可以减少颜色的失真.。
实现代码:
# 1.60 彩色图像的直方图匹配
import cv2
import numpy as np
path = r"E:\PS\2.png"
def hisEqulColor2(imga): #直方图均衡化算法
ycrcb = cv2.cvtColor(imga, cv2.COLOR_BGR2YCR_CB) # 转换ycrb颜色空间
channels = cv2.split(ycrcb)
print(channels)
clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(11,11)) # 局部直方图均衡化
clahe.apply(channels[0], channels[0])
cv2.merge(channels, ycrcb)
cv2.cvtColor(ycrcb, cv2.COLOR_YCR_CB2BGR, imga)
return imga
img = cv2.imread(path)
his = hisEqulColor2(img)
cv2.imshow("result", his)
cv2.imshow("img", img)
cv2.waitKey(0)
效果:
同上面方法相比颜色失真较少,并且不会过度拉伸图像,图像亮度提升可以使用伽马变换或对数变换