直方图
- 直方图定义
- mask操作
- 直方图均衡化
- 均衡化效果
- 自适应直方图均衡化
直方图定义
hist = cv2.calcHist(images, channels, mask, histSize, ranges, …) # hist是一个256*1的矩阵,其中每一个值代表了一个灰度值对应的像素点数目
- images:原图像格式为uint8或float32;当传入函数时应用中括号括起来,如[img]
- channels:同样用中括号括起来,它会告诉函数要统计直方图的图像通道;如果传入的是灰度图,它的值就是[0],如果传入的是彩色图像,它的值可以是[0]、[1]、[2],分别对应着BGR
- mask:掩膜图像,如果统计的是整幅图像,它的值就为None
- histSize:BIN的数目,也应用中括号括起来
- ranges:像素值范围,一般为[0, 256],左闭右开
plt.hist(x, bins=None, range=None, …) # 直方图,一种特殊的柱状图
- x:直方图所需数据,必须是一维数组,多维数组可以先扁平化再作图
- bins:直方图的柱数,即要分成的组数,默认为10
- range:tuple or None,如果为None,则默认为(x.min(), x.max()),即x轴的范围
import cv2
import matplotlib.pyplot as plt
img = cv2.imread(r'F:/aixin.jpg', 0) # 0表示灰度图
plt.hist(img.ravel(), 256) # 横轴表示数值(这里是像素值),纵轴表示一个数值出现的次数;img.ravel()可以将二维矩阵img展平成一维数组
plt.show()
import cv2
import matplotlib.pyplot as plt
img = cv2.imread(r'F:/aixin.jpg')
color = ('b', 'g', 'r')
for i, col in enumerate(color):
hist = cv2.calcHist([img], [i], None, [256], [0, 256])
plt.plot(hist, col)
plt.xlim([0, 256])
plt.show()
mask操作
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread(r'F:/aixin.jpg', 0) # 0表示灰度图
mask = np.zeros(img.shape[:2], np.uint8) # 创建一个与二维图像shape相同的0值矩阵
mask[350:700, 350:700] = 255 # 将mask的一部分赋值为255,[H, W]
masked_img = cv2.bitwise_and(img, img, mask=mask) # 与操作
plt.subplot(1, 3, 1)
plt.axis('off') # 设置无坐标
plt.title('source')
plt.imshow(img, 'gray') # 以灰度方式呈现
plt.subplot(1, 3, 2)
plt.axis('off')
plt.title('mask')
plt.imshow(mask, 'gray')
plt.subplot(1, 3, 3)
plt.axis('off')
plt.title('masked_img')
plt.imshow(masked_img, 'gray')
plt.show()
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])
plt.plot(hist_full, 'b')
plt.plot(hist_mask, 'g')
plt.show()
直方图均衡化
图像A的像素分布如下所示:
均衡化过程:
灰度值 | 像素个数 | 概率 | 累积概率 | 根据函数映射后的灰度值 | 取整 |
---|---|---|---|---|---|
50 | 4 | 0.25 | 0.25 | 0.25*(255-0)=63.75 | 64 |
128 | 3 | 0.1875 | 0.4375 | 0.4375*(255-0)=111.5625 | 112 |
200 | 5 | 0.3125 | 0.75 | 0.75*(255-0)=191.25 | 191 |
255 | 4 | 0.25 | 1 | 1*(255-0)=255 | 255 |
均衡化后得到的图像B的像素分布如下所示:
均衡化效果
import cv2
import matplotlib.pyplot as plt
img = cv2.imread(r'F:/aixin.jpg', 0) # 0表示灰度图
equ = cv2.equalizeHist(img) # 均衡化
plt.subplot(1, 2, 1)
plt.title('source')
plt.hist(img.ravel(), 256)
plt.subplot(1, 2, 2)
plt.title('equalized')
plt.hist(equ.ravel(), 256)
plt.show()
res = cv2.hconcat((img, equ))
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
自适应直方图均衡化
equalizeHist这种全局的均衡化也会存在一些问题,由于整体亮度的提升,可能会使得局部图像的细节变得模糊,因此有时我们需要进行分块的局部均衡化操作,称之为自适应直方图均衡化。
clahe = cv2.createCLAHE(clipLimit=None, tileGridSize=None) # 自适应直方图均衡化
cla = clahe.apply(img)
- clipLimit:对比度限制阈值
- tileGridSize:输入图像将被分割成大小相等的矩形块,tileGridSize定义行和列中的块数
img = cv2.imread(r'F:/aixin.jpg', 0) # 原图
equ = cv2.equalizeHist(img) # 均衡化(全局均衡化)
clahe = cv2.createCLAHE(clipLimit=2, tileGridSize=(8, 8)) # 自适应均衡化(分块均衡化)
cla = clahe.apply(img)
res = cv2.hconcat((img, equ, cla))
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image', res)
cv2.waitKey(0)
cv2.destroyAllWindows()