2019-8-13 opencv图像处理10-直方图2(Histogram Equalization )均衡化

64 篇文章 3 订阅

官网https://docs.opencv.org/3.4.1/d5/daf/tutorial_py_histogram_equalization.html

我们来想象一下,一副图像的像素值都集中在某些特定范围之内。例如,明亮的图像,像素值都会很高。

但是一副好图像,像素值应该发布在图像所有区域。所以你需要把直方图横向拉升到2端(如下图),这就是直方图均衡化。通常情况,这种操作会增加图像的对比度。
在这里插入图片描述

直方图均衡化详见 en.wikipedia.org/wiki/Histogram_equalization

现在我们先来看看如何用numpy实现直方图均衡化。

例1,观察以下图像的直方图
在这里插入图片描述
代码如下

import cv2 
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('1.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中的直方图均衡化公式。

1.numpy掩膜数组实现直方图均衡化

这里我们使用了numpy的掩膜数组。对于掩膜数组,所有操作只有对非掩膜(non-masked)元素有效。

# 构建Numpy 掩模数组。cdf 为原数组,当数组元素为0 时掩盖(计算时被忽略)。
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
# 对被掩盖的元素赋值为0
cdf = np.ma.filled(cdf_m,0).astype('uint8')

然后我们就获得了一个表,这个表中给我们提供了每一个输入像素值对应的输出像素值。
最后我们把它应用到图像上。

img2 = cdf[img]

例1,利用numpy掩膜数组实现直方图均衡化

import cv2 
import numpy as np
from matplotlib import pyplot as plt


img = cv2.imread('1.jpg',0)

hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()

# 构建Numpy 掩模数组。cdf 为原数组,当数组元素为0 时掩盖(计算时被忽略)。
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
# 对被掩盖的元素赋值为0
cdf = np.ma.filled(cdf_m,0).astype('uint8')

img2 = cdf[img]

cv2.imshow('result', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
显示结果如上,对比度明显增加。

例2,显示numpy掩膜数组均衡化后直方图

import cv2 
import numpy as np
from matplotlib import pyplot as plt


img = cv2.imread('1.jpg',0)

hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()

# 构建Numpy 掩模数组。cdf 为原数组,当数组元素为0 时掩盖(计算时被忽略)。
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
# 对被掩盖的元素赋值为0
cdf = np.ma.filled(cdf_m,0).astype('uint8')

img2 = cdf[img]

hist,bins = np.histogram(img2.flatten(),256,[0,256])
cdf = hist.cumsum()

cdf_normalized = cdf * float(hist.max()) / cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(img2.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()

在这里插入图片描述
直方图(红色)和累积分布图(蓝色)如上。

关于直方图均衡化另外一个重要特点是,如果输入的图像是一个比较暗的图像(不像上面例子中使用的是比较亮的图像),在均衡化后也会得到和上面一样的结果。
所以直方图均衡化被作为一个参考工具,用于使所有图像获得相同的亮度条件。这在很多案例中都有用。

例如,人脸识别场景,在对人脸数据图像进行训练之前,先进行直方图均衡化,使所有图像都有相同的亮度条件。

2.opencv中的直方图均衡化

opencv提供cv.equalizeHist()函数实现均衡化。输入是灰度图,输入的是均衡化后的直方图。

例,opencv中实现直方图均衡化

import cv2 
import numpy as np
from matplotlib import pyplot as plt


img = cv2.imread('1.jpg',0)

equ = cv2.equalizeHist(img)
res = np.hstack((img,equ)) #stacking images side-by-side
cv2.imwrite('res.png',res)

在这里插入图片描述
同样使用的是numpy掩膜数组均衡化例子中图像,显示对比结果如上。

当图像中的直方图数据集中在某个区域时候,均衡化就非常有用了。但是如果灰度变化非常强烈,同时分布范围非常大时候,均衡化的效果并不好。例如:图像中既有亮的像素点又有暗的像素点。

3.CLAHE (Contrast Limited Adaptive Histogram Equalization) -对比度有限自适应直方图均衡化

上面例子中的均衡化,可以发现都是进行全图像对比度变化。但是很多情况下,这样并不好。例如,观察下图,特别是进行全图均衡化后的效果。
在这里插入图片描述
可以发现,均衡化后,背景的对比度有了提高。但是对比上下2幅图雕像的脸部,由于过亮丢失了很多信息。这是因为直方图均衡化时候并没有考虑特别的区域。

为了解决这个问题,需要使用自适应直方图均衡化。此时,图像会被分成许多个小块,每个小块被称为“tiles”(opencv中默认tiles大小是8*8)。然后每个小块分别进行均衡化。所以每一个小块中,直方图被限制在小区域中(除非有噪声)。如果有噪声,它会被放大,要避免这个问题,就要使用对比度限制。如果有任何一个直方图的bin值超过对比度限制值(opencv中默认40),在直方图均衡化之前,把那些像素均匀分散到其他bin中。均衡化后,为了消除tiles之间的边界,使用双线性差值。

例,对比度限制自适应直方图均衡化

import cv2 
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('a.jpg',0)

# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv2.imwrite('clahe_2.jpg',cl1)

在这里插入图片描述
结果如上,雕塑的脸部是不是好很多了?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值