走进opencv-python 7 直方图以及均衡化

前言

本节将要介绍直方图以及直方图的均衡化

一、直方图

1.1

什么是直方图呢?直方图是对图像的灰度分布的展示。直方图的 x 轴是灰度值(0 到 255),y 轴是图片中具有同一个灰度值的点的数目。直方图的左边区域像是了暗一点的像素数量,右侧显示了亮一点的像素的数量。
调用函数cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])可以实现直方图的计算

参数介绍:

1. images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该用中括号 [] 括起来,例如:[img]。
2. channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
3. mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。(后边有例子)
4. histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。
5. ranges: 像素值范围,通常为 [0,256]

img = cv2.imread('longmao.png',0)
hist = cv2.calcHist([img],channels=[0],mask=None,
                    histSize=[256],ranges=[0,256])
print(hist.shape)

结果返回(256,1)的数组。

那么如何绘制出直方图呢?

可以使用 Matplotlib 中的绘图函数

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

img = cv2.imread('longmao.png',0)
hist = cv2.calcHist([img],channels=[0],mask=None,
                    histSize=[256],ranges=[0,256])
plt.figure()
plt.plot(hist)
plt.xlim((0,256))
plt.show()

结果:

1.2 掩膜mask

有时我们只关心图像某个局部区域的直方图,这时需要构建一副掩模图像。将要统计的部分设置成白色,然后把这个掩模图像传给函数就可以了 。

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

img = cv2.imread('longmao.png',0)
mask = np.zeros(img.shape[:2],np.uint8)
mask[100:200,100:200] = 255
mask_img = cv2.bitwise_and(img,img,mask=mask)
res = np.c_[img,mask_img]
hist_mask = cv2.calcHist([img],[0],mask=mask,histSize=[256],ranges=[0,256])
plt.figure()
plt.plot(hist_mask)
plt.xlim((0,256))
plt.show()
cv2.imshow('mask_img',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

1.3 直方图均衡化

如果一副图像中的大多是像素点的像素值都集中在一个像素值范围之内会怎样呢?例如,如果一幅图片整体很亮,那所有的像素值应该都会很高。但是一副高质量的图像的像素值分布应该很广泛。所以你应该把它的直方图做一个横向拉伸(如下图),这就是直方图均衡化要做的事情。通常情况下这种操作会改善图像的对比度。

    Histograms Equalization

OpenCV 中的直方图均衡化函数为 cv2.equalizeHist()。这个函数的输入图片仅仅是一副灰度图像,输出结果是直方图均衡化之后的图像

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

img = cv2.imread('longmao.png',0)
equ_img = cv2.equalizeHist(img)
res = np.c_[img,equ_img]

cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

img_hist = cv2.calcHist([img],[0],mask=None,histSize=[256],ranges=[0,256])
equ_img_hist = cv2.calcHist([equ_img],[0],mask=None,histSize=[256],ranges=[0,256])

plt.figure()
plt.subplot(121)
plt.title('img_hist')
plt.plot(img_hist)

plt.subplot(122)
plt.title('equ_img_hist')
plt.plot(equ_img_hist)

plt.show()

结果:

 

2 CLAHE

  上面做的直方图均衡化会改变整个图像的对比度,但是在很多情况下,这样做的效果并不好。
为了解决这个问题,我们需要使用自适应的直方图均衡化。这种情况下,整幅图像会被分成很多小块,这些小块被称为“tiles”(在 OpenCV 中 tiles 的大小默认是 8x8),然后再对每一个小块分别进行直方图均衡化(跟前面类似)。
  所以在每一个的区域中,直方图会集中在某一个小的区域中(除非有噪声干扰)。如果有噪声的话,噪声会被放大。为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的 bin 超过对比度的上限的话,就把其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。最后,为了去除每一个小块之间“人造的”(由于算法造成)边界,再使用双线性差值,对小块进行缝合。
下面的代码显示了如何使用 OpenCV 中的 CLAHE。

img = cv2.imread('longmao.png',0)
#cilpLimit 对比度大小 tileGridSize块大小
clahe = cv2.createCLAHE(clipLimit=5,tileGridSize=(8,8))
equ_img = clahe.apply(img)
res = np.c_[img,equ_img]

cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

 结果:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值