当图像灰度级范围较小时,会造成图像对比度较低的问题。而图像增强则是通过把图像的灰度级范围进行扩大,从而使图像细节看起来更加清晰。下面我们一步一步进行说明。
灰度直方图
直方图是对灰度图像上的灰度值进行统计得到的关于灰度值的函数,用来描述每个灰度值在图像矩阵的像素个数或占有率。以下面的植物图片为例:
import cv2import matplotlib.pyplot as plt# 绘制图像灰度直方图def deaw_gray_hist(gray_img):''':param gray_img大小为[h, w]灰度图像'''# 获取图像大小h, w = gray_img.shapegray_hist = np.zeros([256])for i in range(h):for j in range(w):gray_hist[gray_img[i][j]] += 1x = np.arange(256)# 绘制灰度直方图plt.bar(x, gray_hist)plt.xlabel("gray Label")plt.ylabel("number of pixels")plt.show()# 读取图片img = cv2.imread(img_path) # 这里需要指定一个 img_pathdeaw_gray_hist(img[:,:,0])cv2.imshow('ori_img', img)cv2.waitKey()
如下所示,左边为植物图片,右边为其对应的灰度直方图。从直方图可以看出其灰度值主要聚集在范围很小的一个区域里,所以导致植物图片对比度较低,不太清晰。
线性变换
我们把图像的灰度直方图看做是关于图像灰度值的一个函数,即每张图片都可以得到一个关于其灰度值的分布函数。我们可以通过线性变换让其灰度值的范围变大。
假设图片上某点的像素值为 iii,经过线性变换后得到的像素值为 ooo , a,ba , ba,b 为线性变换的参数则:
o=a∗i+bo = a*i +bo=a∗i+b
其中当 a>0a>0a>0 时,图片的对比度会增大;当 0<a<10<a<10<a<1时,图片的对比度会减小。当 b>0b>0b>0 时,图片的亮度会增大;当 b<0b<0b<0时,图片的亮度会减小。
# 对图像进行 线性变换def linear_transform(img, a, b):''':param img: [h, w, 3] 彩色图像:param a: float 这里需要是浮点数,把图片uint8类型的数据强制转成float64:param b: float:return: out = a * img + b'''out = a * img + bout[out > 255] = 255out = np.around(out)out = out.astype(np.uint8)return out# a = 2, b=10img = linear_transform(img, 2.0, 10)deaw_gray_hist(img[:, :, 0])cv2.imshow('linear_img', img)cv2.waitKey()
直方图正规化
设图片III的灰度值范围为[Imin,Imax][I_{min}, I_{max}][Imin,Imax],而输出图片OOO的灰度值范围[Omin,Omax][O_{min},O_{max}][Omin,Omax],当前图片第rrr行第ccc列的灰度值表示为Ir,cI_{r,c}Ir,c,同样输出图片对应位置的灰度值表示为Or,cO_{r,c}Or,c,它们之间的映射关系为:
Or,c−OminIr,c−Imin=Omax−OminImax−Imin\frac{O_{r,c}-O_{min}}{I_{r,c}-I_{min}} = \frac{O_{max}-O_{min}}{I_{max}-I_{min}}Ir,c−IminOr,c−Omin=Imax−IminOmax−Omin
该式子可以转换为:
Or,c=Omax−OminImax−Imin∗(Ir,c−Imin)+Omin=(Omax−OminImax−Imin)∗Ir,c+(Omin−Omax−OminImax−Imin∗Imin)O_{r,c} = \frac{O_{max}-O_{min}}{I_{max}-I_{min}} * (I_{r,c}-I_{min}) + O_{min} \\=(\frac{O_{max}-O_{min}}{I_{max}-I_{min}})*I_{r,c}+( O_{min}-\frac{O_{max}-O_{min}}{I_{max}-I_{min}}*I_{min})Or,c=Imax−IminOmax−Omin∗(Ir,c−Imin)+Omin=(Imax−IminOmax−Omin)∗Ir,c+(Omin−Imax−IminOmax−Omin∗Imin)
该式子最后可以转换成线性变换的形式,直方图正规化是一种自动选择a和b值的一种线性变换方法。
def normalize_transform(gray_img):''':param gray_img::return:'''Imin, Imax = cv.minMaxLoc(gray_img)[:2]Omin, Omax = 0, 255# 计算a和b的值a = float(Omax - Omin) / (Imax - Imin)b = Omin - a * Iminout = a * gray_img + bout = out.astype(np.uint8)return outb = img[:, :, 0]g = img[:, :, 1]r = img[:, :, 2]b_out = normalize_transform(b)g_out = normalize_transform(g)r_out = normalize_transform(r)nor_out = np.stack((b_out, g_out, r_out), axis=-1)deaw_gray_hist(nor_out[:, :, 0])cv.imshow('nor_out', nor_out)cv2.waitKey()
因为植物原图本身的灰度值范围就很接近[0,255][0, 255][0,255],所以经过直方图正规化后效果并不明显。
直方图均衡
直方图均衡步骤如下:
计算图像的灰度直方图计算灰度直方图的累加直方图得到输入灰度级和输出灰度级之间的映射关系
设输入的灰度级为 ppp,输出的灰度级为 qqq。
q+1256=∑k=0phistkH∗W\frac{q+1}{256}=\frac{\sum_{k=0}^phist_{k}}{H*W}256q+1=H∗W∑k=0phistk
# 对图像进行 均衡化def equalize_transfrom(gray_img):return cv.equalizeHist(gray_img)b = img[:, :, 0]g = img[:, :, 1]r = img[:, :, 2]b_out = equalize_transfrom(b)g_out = equalize_transfrom(g)r_out = equalize_transfrom(r)equa_out = np.stack((b_out, g_out, r_out), axis=-1)deaw_gray_hist(equa_out[:, :, 0])cv.imshow('equa_out', equa_out)cv2.waitKey())
参考链接:
OpenCV–Python 图像增强