OpenCV 图像变换之 —— 直方图均衡化

本文最后更新于:2022年5月21日 凌晨

本文摘录 OpenCV 中的图像变换相关操作内容,重点介绍 Opencv 中的直方图均衡化操作。

直方图均衡

相机和图像传感器不仅可以适应场景中自然产生的对比度,还可以管理图像传感器在可用的光照水平下的曝光程度。在标准相机中,设置快门和镜头光圈以确保传感器既不太多也不太少。然而,对于传感器的可用动态范围,特定图像中的对比度范围往往太大。因此,捕获需要更长曝光时间的黑暗区域(例如阴影)和需要更短曝光的明亮区域之间存在权衡,以避免饱和“白化”。在许多情况下,在同一个图像中二者不可兼得。

  • 直方图均衡数学背景是将一个分布(强度值的给定直方图)映射到另一个分布(强度值的更宽和理想的均匀分布)。也就是说,我们希望在新分配中尽可能均匀分布原始分布的y值。事实证明,解决扩展分布值的问题的一个好方法是:重映射函数应该是累积分布函数。如图所示,展示了累积分布函数的一个例子,对于原始纯高斯的密度分布有些理想化的情况。然而,累积密度可以应用于任何分布,原始分布的运行总和从负到正的范围。

  • 我们可以使用累积分布函数将原始分布重新映射到均匀分布,只需查看原始分布中的每个y值,并查看在均衡分布中应该进行的位置。对于连续分布结果将是一个精确的均衡,但是对于数字离散分布,结果可能很不一致。

cv2.calcHist()

直方图统计

官方文档

1
2
3
4
5
6
7
8
9
10
cv2.calcHist(
images, # 源图像
channels, # 用于统计直方图的通道列表
mask, # 可选的遮罩。如果矩阵不是空的,它必须是一个与图像大小相同的8位数组。
histSize, # 每个维度的直方图大小数组。
ranges[, # 每个维度中直方图面元边界的整数数组。
hist[, # 输出直方图
accumulate]]) # 积累标记。如果被设置,则柱状图在开始时不会被清除。
# 这个特性使您能够计算几组数组的单个直方图,或者及时更新直方图。
-> hist
  • 示例代码
1
2
3
img = mt.cv_rgb_imread('img2_gray.jpg', gray=True)
hist = cv2.calcHist([img], [0], None, [256], [0,255])
PIS(img, hist[:, 0])

  • numpy 也可以实现该直方图功能
1
2
3
hist_cv = cv2.calcHist([img],[0],None,[256],[0,256])
hist_np,bins = np.histogram(img.ravel(),256,[0,256])
hist_np2 = np.bincount(img.ravel(),minlength=256)

cv2.equalizeHist()

灰度图的直方图均衡化

官方文档

  • 函数使用
1
2
3
cv2.equalizeHist(
src[, # 源图像
dst]) -> dst
  • 示例代码
1
2
3
4
5
img = mt.cv_rgb_imread('img2_gray.jpg', gray=True)
hist = cv2.calcHist(img, [0], None, [256], [0,255])
res = cv2.equalizeHist(img)
res_hist = cv2.calcHist(res, [0], None, [256], [0,255])
PIS(img, hist[:, 0], res, res_hist[:, 0], cmap='gray')

参考资料