小杰机器视觉(five day)——直方图均衡化
1.直方图均衡化
(1)概念
一张好的图像通常在直方图上分布比较均匀,这样的图像对比度比较强烈(明暗差别大)。直方图均衡化可以提升原图的观感,需要遍历图像的像素,统计每个灰度值出现的频数、比例与累积比例,并重新映射到新的范围(如0-255,或其他范围),从而提升图像的观感。
均衡化之后的图像显示效果会更加强烈,具有广泛地应用前景:
- 医学影像处理
X光、CT扫描、核磁共振
- 摄影与监控
改善照片的对比度和色彩平衡提升观感
- 卫星影像处理
可以增加图像质量,提高解析度
(2)原始直方图均衡化
可以通过虚拟仿真实验的直方图均衡化节点,选择hist_method(直方图均衡化方法)中的equalizeHist参数设置为原始的直方图均衡化算法。
通过调整图像像素值的分布,使图像的对比度和亮度得到改善。
算法过程如下:
统计数据→
假设有一个3*3的图像,其灰度如上图所示,先统计每个像素值的频数、比例与累计比例,统计完成后,代入下面的公式:
新的像素值 = 要缩放的范围(通常为0-255)* 该像素的累计比例
比如灰度为50的像素点,范围255*累积比例0.33=84.15,取整后为84,使用灰度值84替换原图中50灰度值的像素点。原始图像src中所有的灰度值都带入以上公式,算出它们在目标图像dst中的新的灰度值,如下图所示。
代码
import cv2
import numpy as np# 直方图绘制函数
def draw_hist(image, color):"""绘制直方图:param image: 哪个图的直方图图像(灰度化之后的):param color: 直方图柱子什么颜色,BGR元组:return: 直方图图像"""hist = cv2.calcHist([image], # 计算直方图的图像,支持多图像输入,因此一个图像也要写成列表[0], # 要计算的图像灰度值通道需要,灰度图直接传0None, # 掩膜,全图计算不需要[256], # 直方图x轴的精细程度,256表示分为256份[0, 255] # x轴的范围)print(hist.shape) # (256, 1) 256表示有256个灰度频数数据# 提取关键数据min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(hist)# print('min_val:', min_val) # 0.0,最小的灰度频数print('max_val:', max_val) # 471606.0,最大的灰度频数# print('min_loc:', min_loc) # (0, 255),最小的灰度频数对应的灰度值# print('max_loc:', max_loc) # (0, 1),最大的灰度频数对应的灰度值# 创建一张纯黑图,画柱子hist_img = np.zeros([256, 256, 3], np.uint8)# 为了让y轴最高的柱子留一部门空白,最高柱子的高度hpt = int(256 * 0.9)for h in range(256): # 从0到255,每个灰度画柱子# 柱子高度(整数) = 直方图的最高值hpt * 每个灰度的频数/最高的频数intensity = int(hpt * hist[h] / max_val)# print(intensity)# 画柱子(线)cv2.line(hist_img,(h, 256), # x轴的起始点(h, 256 - intensity), # 线段从下往上画的终点color)return hist_imgif __name__ == '__main__':# 1. 图片输入path = 'ct.png'image_np = cv2.imread(path)# 2. 灰度化image_np_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)# 3. 绘制直方图color = {'red': (0, 0, 255),'green': (0, 255, 0),'blue': (255, 0, 0)}hist_img = draw_hist(image_np_gray, color['green'])# 4. 直方图均衡化equ_hist_image_np = cv2.equalizeHist(image_np_gray)# 5. 绘制直方图eqi_hist_img = draw_hist(equ_hist_image_np, color['red'])# 6. 图片输出cv2.imshow('hist_img', hist_img)cv2.imshow('eqi_hist_img', eqi_hist_img)cv2.imwrite('equ_hist_image_np.jpg', equ_hist_image_np)cv2.waitKey(0)
(3)自适应均衡化
在直方图均值化节点中,选择hist_method为createCLAHE(自适应均衡化,对比度受限的自适应均衡化)方法。
这种方法可以在小区域(8*8)内进行直方图均衡化,因此将对比度进行了限制。如果小区域内有噪声,也会被放大,需要对小区域进行对比度限制。
主要步骤如下:
1. 将图像分为大小相同的矩形块,块分的越细,相对效果越好。
2. 统计每个块的直方图信息,并生成每个块单独的直方图H。
3. 根据设置的限制参数强度,对直方图信息重新分配。
(a)设定一个阈值T,将均衡化后的直方图从H[0]到H[255](灰度0-255,即x轴)上依次遍历,把大于阈值T的都全部减去,并统计一共减去了多少个像素。
(b)将减去的像素值的和除以缩放的范围(256),添加到每个灰度值的频数。
4. 重复2、3步骤,直到全图所有的块计算完成。
5. 为了再次减少块状效应,对每个小块进行双线性插值。
注意:
- 把原始图像分为小块处理时,如果不是整数倍,默认内部使用BORDER_REFLECT_101进行边界填充,以此来保证分割的是整数倍。
- 双线性插值计算不公平问题
(a)对于四个角点(红色),直接使用均衡化之后的像素值。
(b)对于在frame上的像素点(绿色),进行单线性插值。
(c)其他情况的像素点(蓝色),进行双线性插值。
下面是自适应均衡化的相关参数:
- clipLimit
对比度限制阈值
- tileGridSize
小区块范围,推荐8*8
代码
import cv2
import numpy as np# 直方图绘制函数
def draw_hist(image, color):"""绘制直方图:param image: 哪个图的直方图图像(灰度化之后的):param color: 直方图柱子什么颜色,BGR元组:return: 直方图图像"""hist = cv2.calcHist([image], # 计算直方图的图像,支持多图像输入,因此一个图像也要写成列表[0], # 要计算的图像灰度值通道需要,灰度图直接传0None, # 掩膜,全图计算不需要[256], # 直方图x轴的精细程度,256表示分为256份[0, 255] # x轴的范围)print(hist.shape) # (256, 1) 256表示有256个灰度频数数据# 提取关键数据min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(hist)# print('min_val:', min_val) # 0.0,最小的灰度频数print('max_val:', max_val) # 471606.0,最大的灰度频数# print('min_loc:', min_loc) # (0, 255),最小的灰度频数对应的灰度值# print('max_loc:', max_loc) # (0, 1),最大的灰度频数对应的灰度值# 创建一张纯黑图,画柱子hist_img = np.zeros([256, 256, 3], np.uint8)# 为了让y轴最高的柱子留一部门空白,最高柱子的高度hpt = int(256 * 0.9)for h in range(256): # 从0到255,每个灰度画柱子# 柱子高度(整数) = 直方图的最高值hpt * 每个灰度的频数/最高的频数intensity = int(hpt * hist[h] / max_val)# print(intensity)# 画柱子(线)cv2.line(hist_img,(h, 256), # x轴的起始点(h, 256 - intensity), # 线段从下往上画的终点color)return hist_imgif __name__ == '__main__':# 1. 图片输入path = 'ct.png'image_np = cv2.imread(path)# 2. 灰度化image_np_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)# 3. 绘制直方图color = {'red': (0, 0, 255),'green': (0, 255, 0),'blue': (255, 0, 0)}hist_img = draw_hist(image_np_gray, color['green'])# 4. 直方图均衡化# equ_hist_image_np = cv2.equalizeHist(image_np_gray)# 创建自适应直方图均衡化的参数对象clahe = cv2.createCLAHE(clipLimit=3, # 对比度限制阈值tileGridSize=(80, 80) # 小区域面积)# 自适应直方图均衡化equ_hist_image_np = clahe.apply(image_np_gray)# 5. 绘制直方图eqi_hist_img = draw_hist(equ_hist_image_np, color['red'])# 6. 图片输出cv2.imshow('hist_img', hist_img)cv2.imshow('eqi_hist_img', eqi_hist_img)cv2.imwrite('equ_hist_image_np3.jpg', equ_hist_image_np)cv2.waitKey(0)
效果
原图
直方图均衡化
自适应直方图均衡化