前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >opencv(4.5.3)-python(二十四)--直方图均衡化

opencv(4.5.3)-python(二十四)--直方图均衡化

作者头像
用户9875047
发布2023-02-26 15:13:29
1.1K0
发布2023-02-26 15:13:29
举报
文章被收录于专栏:机器视觉全栈er

翻译及二次校对:cvtutorials.com

目标

在本节中:

  • • 我们将学习直方图均衡化的概念,并利用它来改善我们图像的对比度。

理论

考虑一个图像,其像素值只局限于某些特定的数值范围。例如,较亮的图像将有所有的像素限制在高值。但是一个好的图像会有来自图像所有区域的像素。因此,你需要将这个直方图拉伸到两端(如下图所示,来自维基百科),这就是直方图均衡化的作用(简单地说)。这通常会改善图像的对比度。

我建议你阅读关于直方图均衡化的维基百科页面,以了解更多相关细节。它有一个非常好的解释,并有例子,所以在阅读后你会理解几乎所有的东西。相反,在这里我们将看到它的Numpy实现。之后,我们将看到OpenCV函数。

代码语言:javascript
复制
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('wiki.jpg',0)
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf * float(hist.max()) / cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()

你可以看到直方图位于较亮的区域。我们需要完整的光谱。为此,我们需要一个转换函数,将较亮区域的输入像素映射到完整区域的输出像素。这就是直方图均衡化的作用。

现在我们找到直方图的最小值(不包括0),然后应用wiki页面中给出的直方图均衡化公式。但我在这里使用了Numpy中的掩膜数组概念。对于掩膜数组,所有的操作都是在非掩膜的元素上进行的。你可以从Numpy关于掩膜数组的文档中读到更多关于它的信息。

代码语言:javascript
复制
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint8')

现在我们有了查找表,它为我们提供了关于每个输入像素值的输出像素值的信息。所以我们只需应用转换。

代码语言:javascript
复制
img2 = cdf[img]

现在我们像以前一样计算它的直方图和Cdf(你来做),结果看起来像下面。

另一个重要的特点是,即使图像是一个较暗的图像(而不是我们使用的一个较亮的图像),在均衡后,我们将得到与上述图像几乎相同的图像。因此,这被用作一个 "参考工具",使所有图像具有相同的照明条件。这在许多情况下是很有用的。例如,在人脸识别中,在训练人脸数据之前,对人脸图像进行直方图均衡化,使其具有相同的照明条件。

OpenCV中的直方图均衡化

OpenCV有一个函数可以做到这一点,即cv.equalizeHist()。它的输入是灰度图像,输出是我们的直方图均衡化图像。

下面是一个简单的代码片段,显示了它在我们使用的同一图像上的用法。

代码语言:javascript
复制
img = cv.imread('wiki.jpg',0)
equ = cv.equalizeHist(img)
res = np.hstack((img,equ)) #stacking images side-by-side
cv.imwrite('res.png',res)

因此,现在你可以在不同的光线条件下拍摄不同的图像,对其进行均衡并检查结果。

当图像的直方图被限制在一个特定的区域内时,直方图均衡化是好的。在灰度变化较大的地方,即直方图覆盖较大区域的地方,它不会有好的效果,也就是说,明亮和黑暗的像素都存在。请查看附加资源中的SOF链接。

CLAHE(对比度有限的自适应直方图均衡)

我们刚才看到的第一个直方图均衡,考虑了图像的整体对比度。在许多情况下,这并不是一个好主意。例如,下面的图片显示了一张输入图片和全局直方图均衡化后的结果。

诚然,在直方图均衡化之后,背景对比度得到了改善。但比较两张图片中的雕像的脸。由于过亮,我们失去了大部分的信息。这是因为它的直方图并不像我们在以前的案例中看到的那样被限制在一个特定的区域内(试着绘制输入图像的直方图,你会得到更多的直观感受)。

因此,为了解决这个问题,采用了自适应直方图均衡化。在这个过程中,图像被分成小块,称为 "瓦片"(OpenCV中瓦片大小默认为8x8)。然后这些块中的每一个都像往常一样被直方图均衡化。因此,在一个小区域内,直方图将被限制在一个小区域内(除非有噪声)。如果有噪音,它就会被放大。为了避免这种情况,采用了对比度限制。如果任何一个直方图仓超过了指定的对比度限制(在OpenCV中默认为40),在应用直方图均衡化之前,这些像素会被剪掉并均匀地分布到其他仓。在均衡化之后,为了消除瓦片边界的伪影,将应用双线性插值。

下面的代码片段显示了如何在OpenCV中应用CLAHE。

代码语言:javascript
复制
import numpy as np
import cv2 as cv
img = cv.imread('tsukuba_l.png',0)
# create a CLAHE object (Arguments are optional).
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv.imwrite('clahe_2.jpg',cl1)

请看下面的结果,并与上面的结果进行比较,特别是雕像区域。

其他资源

  1. 1. 维基百科关于直方图均衡化的页面[1]
  2. 2. Numpy中的掩膜数组[2]

还可以查看这些关于对比度调整的SOF问题。

  1. 1. 我如何在OpenCV中用C语言调整对比度?[3]
  2. 2. 如何用opencv均衡图像的对比度和亮度?[4]
引用链接

[1] 维基百科关于直方图均衡化的页面: https://en.wikipedia.org/wiki/Histogram_equalization [2] Numpy中的掩膜数组: https://docs.scipy.org/doc/numpy/reference/maskedarray.html [3] 我如何在OpenCV中用C语言调整对比度?: https://stackoverflow.com/questions/10549245/how-can-i-adjust-contrast-in-opencv-in-c [4] 如何用opencv均衡图像的对比度和亮度?: https://stackoverflow.com/questions/10561222/how-do-i-equalize-contrast-brightness-of-images-using-opencv

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-01-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器视觉全栈er 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引用链接
相关产品与服务
人脸识别
腾讯云神图·人脸识别(Face Recognition)基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、比对、搜索、验证、五官定位、活体检测等多种功能,为开发者和企业提供高性能高可用的人脸识别服务。 可应用于在线娱乐、在线身份认证等多种应用场景,充分满足各行业客户的人脸属性识别及用户身份确认等需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档