![3db291f360eebc1fb149a3fce0f575e4.png](https://i-blog.csdnimg.cn/blog_migrate/623efe69eeec0f1b5a2e9c7399bb8a00.jpeg)
实现环境:
python : 3.6.10
Opencv : 4.1.2
IDE : pycharm
预操作:
1.import cv2
2.import numpy as np
3.import matplotlib.pyplot as plt
4.
5.# 定义函数
6.def cv_show(name, img):
7. cv2.imshow(name, img)
8. cv2.waitKey(0)
9. cv2.destroyAllWindows()
图像直方图简述:直方图是什么?您可以将直方图视为图形或绘图,从而可以总体了解图像的强度分布。它是在X轴上具有像素值(不总是从0到255的范围),在Y轴上具有图像中相应像素数的图。通过查看图像的直方图,您可以直观地了解该图像的对比度,亮度,强度分布等。
![2153c92631081bc8209b70ef0de542db.png](https://i-blog.csdnimg.cn/blog_migrate/72053b6dc907bbf9889c59cbffbb6305.jpeg)
如图:我们可以看到直方图左侧区域显示图中较暗像素的数量,右侧区域显示图中明亮像素的数量。(当然,此直方图是针对灰度图像绘制的)
在Opencv中实现图像直方图的查找、绘制和分析:
我们使用cv2.calcHist()查找直方图:
1.cat = cv2.imread('cat.jpg', 0) # 此处0为读取该图像灰度图的意思
2.cv_show('cat', cat)
![6bdf52d5b3869a5f2e3ca0a76be74253.png](https://i-blog.csdnimg.cn/blog_migrate/72ec30c3b4569a1aae44a2ad36f375b0.jpeg)
在Opencv中调用 calcHist() 函数可以实现对图像像素点直方图的绘制
calcHist(img, channels, mask, histSize, ranges[, hist [, accumulate]])
· 参数解释:
- img: 一般转灰度图,要求原图像格式为Uint8或float32, 传入函数时要使用方括号“[ ]”
- channels: 直方图 同样使用[ ]输入进去, 如果输入图像为灰度图像其值为0;如果是彩色图像为[0],[1],[2]
- mask: 掩码 如果统计整幅图为None , 如果只想统计特点部分图像的直方图则要制作一个掩模图像并使用它
- histSize:这表示我们的BIN计数。BINS:表示直方图显示每个像素值的像素数,即从0到255。但当我们只需找到像素值间隔中的像素数怎么办?比如在0-15间隔内的像素数,对于图像来说,像素数的值在0-256之间,所以我们只需将直方图分成16个子部分。每个子部分的值就是其中所有像素数的和。每个子部分称为一个“BIN”。在opencv中,BINS由histSize表示。
- ranges:表示RANGE,通常为[0, 256],RANGE:表示要测量的强度值范围。
1.hist = cv2.calcHist([cat], [0], None, [256], [0, 256])
2.plt.hist(cat.ravel(), 256)
3.plt.show()
![327c9d13941e3a34e16308a31c9cbe2f.png](https://i-blog.csdnimg.cn/blog_migrate/0c88096365f5cb0b6d6021f7668082de.png)
我们也可以使用Numpy中的 np.histogram()函数来计算图像的直方图:
1.hist,bins = np.histogram(img.ravel(),256,[0,256])
但Numpy中bin的值将具有257个元素,因为Numpy计算出bin的范围为0-0.99、1-1.99、2-2.99等。因此最终范围为255-255.99。为了表示这一点,Numpy在最后添加了256。
但值得注意的是opencv函数比np.histogram()快大约40倍。因此,我们尽可能使用opencv函数。
使用matplotlib绘制三通道直方图:
1.cat = cv2.imread('cat.jpg')
2.cv_show('cat', cat)
![32434bc2b0b97cb0c17820cfdfb9108c.png](https://i-blog.csdnimg.cn/blog_migrate/64c45e2f7793c0b7fec0bbed26c5d941.jpeg)
输出三通道的像素点直方图:
1.color = ('b', 'g', 'r')
2.for i, col in enumerate(color):
3. histr = cv2.calcHist([cat], [i], None, [256], [0, 256])
4. plt.plot(histr, color=col)
5. plt.xlim([0, 256])
6.plt.show()
![aae2ab3bd45ec3f819da8c205d53a098.png](https://i-blog.csdnimg.cn/blog_migrate/147524237e8e562097737af335dc9030.png)
进行掩码操作:
图像的掩码操作是指通过掩码核算子重新计算图像中各个像素的值,掩码核算子刻画领域像素点对新像素值得影响程度,同时根据掩码算子中权重因子对像素点进行加权平均。图像掩码操作常用于图像平滑、边缘检测、特征分析等区域。
1.mask = np.zeros(cat.shape[:2], np.uint8) # 创建掩码
2.mask[100:300, 100:400] = 255
3.
4.mask_cat = cv2.bitwise_and(cat, cat, mask=mask) # 掩码和图片合并
5.cv_show('mask_cat', mask_cat)
![78ab45cd12afdecfc2fb6e702a445170.png](https://i-blog.csdnimg.cn/blog_migrate/bcb76d150bbc737ff227b97337c1df94.png)
绘制掩码操作后的图像直方图:
1.cat_mask = cv2.calcHist([cat], [0], mask, [256], [0, 256])
2.plt.plot(cat_mask)
3.plt.show() # 可发现直方图的y轴值变小
![08acba5ec4e306dcc37a088972ec3a3e.png](https://i-blog.csdnimg.cn/blog_migrate/601f96c4c117dfb61c7d87744549b4dc.png)
直方图均衡化:
考虑到一个图像,它的像素值仅局限于某个特定的值范围,例如,较亮的图像将把所有像素限制在高值上。但是一幅好的图像会有来自图像所有区域的像素。因此,您需要将这个直方图拉伸到两端,这就是直方图均衡化的作用(简单来说)。这通常会提高图像的对比度。
![bfd8c58f742d688f841181ce3ca318c5.png](https://i-blog.csdnimg.cn/blog_migrate/4bf536288a09a8831650dd30d4c2c2dc.png)
得到图像及原像素点直方图:
1.clahe = cv2.imread('clahe.jpg', 0)
2.hist = cv2.calcHist([clahe], [0], None, [256], [0, 256])
3.plt.hist(clahe.ravel(), 256)
4.plt.show()
5.cv_show('1', clahe)
![a1a0a5b089b890b26290da8b8229e300.png](https://i-blog.csdnimg.cn/blog_migrate/62459a2f73e9f5b17f709e2edccf9890.jpeg)
![60c0c00175406edbcb5709eec6f7b08f.png](https://i-blog.csdnimg.cn/blog_migrate/5b3c1a3d7286c1e513a45b9f26939488.png)
(我们可以看到由于图像色调暗,因此直方图位于较暗的区域,我们需要全频谱。为此我们需要一个转换函数,将暗区域的输入像素映射到整个区域的输出像素。这就是直方图均衡化的作用)
进行均衡化 调用 equalizeHist() 函数:
1.equ = cv2.equalizeHist(clahe)
2.plt.hist(equ.ravel(), 256)
3.plt.show()
4.cv_show('2', equ)
![e2131b9220830455a53e7add5a71a90d.png](https://i-blog.csdnimg.cn/blog_migrate/174feec58bdb7cf0ae5c10c3133ad370.jpeg)
![e2d8071b42da1f2f7898eeb620778077.png](https://i-blog.csdnimg.cn/blog_migrate/fa55a91f7d4c7bdb879e9daab2960249.png)
( 经过均衡化后,我们可以看到直方图的亮区域也拥有了值且直方图整体变更平均,这样我们使所有的图像具有相同的照明条件。这种操作在很多领域很常用。例如:在人脸识别中,对人脸数据进行训练之前,对人脸图像进行均衡化处理,使其具有相同的光照条件。)
要注意的是,我们的背景的对比度得到改善。但对于当前图像来说,我们可以很直观的看到,经过均衡化之后图像雕塑的脸由于亮度过高,我们在那里丢失了大量的信息。这是因为在直方图覆盖较大区域(即同时存在亮像素和暗像素)的强度变化较大的地方效果不好。
限制对比度自适应直方图均衡: CLAHE
为了解决这个问题,我们使用自适应直方图均衡化。此时,图像被分成称为“tiles”的小块,在OpenCV中其Size默认为8x8。然后,像执行均衡化操作一样对每一个小块进行均衡。因此,在较小的区域中,直方图将限制在一个较小的区域中(除非存在噪声)。如果有噪音,它将被放大。为了避免这种情况,应用了对比度限制。如果任何直方图bin超出指定的对比度限制(在OpenCV中默认为40),则在应用直方图均衡之前,将这些像素裁剪并均匀地分布到其他bin。均衡后,要消除图块边界中的伪影,请应用双线性插值。
1.clahe1 = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
2.clahe2 = clahe1.apply(clahe)
3.hist1 = cv2.calcHist([clahe2], [0], None, [256], [0, 256])
4.plt.hist(clahe2.ravel(), 256)
plt.show()
![53f8e55c0db7229fc70e791c4b57be9b.png](https://i-blog.csdnimg.cn/blog_migrate/acf5bc50444f0a66b21d1dfff57ba6af.png)
(处理后的直方图,因为其限制对比度均衡的属性,使得得到的直方图在明亮和暗区域都有分布,这种处理方式,有效保证在图像亮暗对比度大的区域信息不会丢失)
最后展示分别处理后的效果图:
![3c266b9309695e9010c39ba4ac32ee72.png](https://i-blog.csdnimg.cn/blog_migrate/98b19fc72ff2553f290bc80da5da680a.jpeg)
另外CLAHE主要是用来克服AHE的过度放大噪音的问题。而AHE为自适应直方图均衡化(Adaptive histgram equalization)
自适应直方图均衡化(AHE):用来提升图像的对比度的一种计算机图像处理技术。和普通的直方图均衡算法不同,AHE算法通过计算图像的局部直方图,然后重新分布亮度来来改变图像对比度。因此,该算法更适合于改进图像的局部对比度以及获得更多的图像细节。
不过,AHE有过度放大图像中相同区域的噪音的问题,另外一种自适应的直方图均衡算法即限制对比度直方图均衡(CLAHE)算法能有限的限制这种不利的放大。
如果对此这两种均衡化算法的原理、实现及效果有兴趣,请访问:
限制对比度自适应直方图均衡化算法原理、实现及效果 - Imageshop - 博客园www.cnblogs.com![65e0148f4f21881a3fd3eaa119d5206a.png](https://i-blog.csdnimg.cn/blog_migrate/313460d30a1ec4a15ef76b8e5737ff02.png)