ImageEnhance Module (PIL 库) 介绍
ImageEnhance Module 包含多个用于图像增强的类(称为 enhancer class),每个类都含有enhance方法:
enhancer.enhance(factor) -> enhanced_image
其中,该方法接收参数 factor,格式为 float,用于控制图像增强的程度(factor 为 1 时,该方法返回原始图像的拷贝;factor 小于 1 时,该方法令输入图像的对比度等属性值减小;factor 小于 1 时,该方法令输入图像的对比度等属性值增大);
该方法返回经图像增强过的图像。
以下是示例代码:
from PIL import Image
from PIL import ImageEnhance
# 原始图像
image = Image.open('test.jpg')
image.show()
#亮度增强
image_brightened = ImageEnhance.Brightness(image).enhance(1.5)
image_brightened.show()
#色度增强
image_colored = ImageEnhance.Color(image).enhance(1.5)
image_colored.show()
#对比度增强
image_contrasted = ImageEnhance.Contrast(image).enhance(1.5)
image_contrasted.show()
#锐度增强
image_sharped = ImageEnhance.Sharpness(image).enhance(1.5)
image_sharped.show()
直方图均衡化(Histogram Equalization)
直方图均衡化的基本思想是把原始图像的直方图通过映射,将其分布变换为均匀分布,这增加了像素灰度值的动态范围,从而可达到增强图像整体对比度的效果。
优点: 思路简单,操作可逆,计算量不大,对大部分场景下的图像有用
缺点: 可能导致图像细节丢失,噪声的对比度增大而有用信息的对比度减小
以下是示例代码:
import cv2
import numpy as np
# 读取原图像
img = cv2.imread('test.jpg')
# 转为灰度图,进行直方图均衡化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
enhanced_gray = cv2.equalizeHist(gray)
cv2.imshow('Enhanced Gray Image',np.hstack([gray,enhanced_gray]))
cv2.waitKey(0)
cv2.destroyWindow('Enhanced Gray Image')
cv2.imwrite('result1.png',np.hstack([gray,enhanced_gray]))
# 直接对 RBG 图像进行直方图均衡化,对每个通道进行均衡化
(B, G, R) = cv2.split(img)
B = cv2.equalizeHist(B)
G = cv2.equalizeHist(G)
R = cv2.equalizeHist(R)
enhanced_img = cv2.merge([B,G,R])
cv2.imshow('Enhanced Color Image',np.hstack([img,enhanced_img]))
cv2.waitKey(0)
cv2.destroyWindow('Enhanced Color Image')
cv2.imwrite('result2.png',np.hstack([img,enhanced_img]))
# 将图像由 RBG 空间转为 YCrCb 空间,对Y通道进行均衡化
YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)
(Y, Cr, Cb) = cv2.split(YCrCb)
Y = cv2.equalizeHist(Y)
enhanced_YCrCb = cv2.cvtColor(cv2.merge([Y, Cr, Cb]), cv2.COLOR_YCR_CB2BGR)
cv2.imshow('Enhanced YCrCb Image',np.hstack([img,enhanced_YCrCb]))
cv2.waitKey(0)
cv2.destroyWindow('Enhanced YCrCb Image')
cv2.imwrite('result3.png',np.hstack([img,enhanced_YCrCb]))
# 直接对 RBG 图像进行自适应局部直方图均衡化,对每个通道进行均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) # create a CLAHE object (Arguments are optional).
(B, G, R) = cv2.split(img)
R, G, B = clahe.apply(R), clahe.apply(G), clahe.apply(B)
enhanced_img = cv2.merge([B,G,R])
cv2.imshow('Enhanced Color Image',np.hstack([img,enhanced_img]))
cv2.waitKey(0)
cv2.destroyWindow('Enhanced Color Image')
cv2.imwrite('result4.png',np.hstack([img,enhanced_img]))
以下为代码运行结果:(左侧为原图,右侧为经过图像增强后的结果)
灰度世界算法(Gray World Algorithm)
灰度世界算法以灰度世界假设为基础,该假设认为:对于一幅有着大量色彩变化的图像,三个分量的平均值趋于同一灰度值。从物理意义上讲,灰色世界法假设自然界景物对于光线的平均反射的均值在总体上是个定值,这个定值近似地为“灰色”。灰度世界算法将这一假设强制应用于待处理图像,可以从图像中消除环境光的影响,获得原始场景图像。
一般有两种方法确定Gray值:
(1) 使用固定值,对于8位的图像(0~255)通常取128作为灰度值 Gray
(2) 计算增益系数,分别计算三通道的平均值 avgR,avgG,avgB,则:Gray=(avgR+avgG+avgB)/3
接着,计算增益系数 kr=Gray/avgR , kg=Gray/avgG , kb=Gray/avgB。利用计算出的增益系数,重新计算每个像素值,构成新的图片
优点: 思路简单,计算量小,
缺点: 当图像场景颜色并不丰富时,尤其出现大块单色物体时,该算法常会失效。
以下是示例代码:
import cv2
import numpy as np
from PIL import Image
# 读取原图像
img = cv2.imread('test.jpg')
# 取三通道的平均值作为灰度值
avgB = np.average(img[:, :, 0])
avgG = np.average(img[:, :, 1])
avgR = np.average(img[:, :, 2])
avg = (avgB + avgG + avgR) / 3
result = np.zeros(img.shape,dtype=np.uint8)
result[:, :, 0] = np.minimum(img[:, :, 0] * (avg / avgB), 255)
result[:, :, 1] = np.minimum(img[:, :, 1] * (avg / avgG), 255)
result[:, :, 2] = np.minimum(img[:, :, 2] * (avg / avgR), 255)
cv2.imshow('Enhanced Image',np.hstack([img,result]))
cv2.waitKey(0)
cv2.destroyWindow('Enhanced Image')
cv2.imwrite('result1.png',np.hstack([img,result]))
以下为代码运行示例:(左侧为原图,右侧为经过图像增强后的结果)
自动白平衡(Automatic White Balance,AWB)
什么是白平衡:假设图像中 R, G, B 最高灰度值对应于图像中的白点,最低灰度值的对应于图像中最暗的点;其余像素点利用 (ax+b) 映射函数把彩色图像中 R, G, B 三个通道内的像素灰度值映射到[0.255]的范围内。(经典算法包括:灰度世界算法,完美反射算法)
白平衡的本质是让白色的物体在任何颜色的光源下都显示为白色,这一点对人眼来说很容易办到,因为人眼有自适应的能力,只要光源的色彩不超出一定的限度,就可以自动还原白色。但相机就不同了,无论是图像传感器还是胶卷都会记录光源的颜色,白色的物体就会带上光源的颜色,白平衡所要做的就是把这个偏色去掉。
import cv2
import numpy as np
from PIL import Image
# 读取原图像
img = cv2.imread('test.jpg')
# 将图像由 RBG 空间转为 LAB 空间
result = cv2.cvtColor(img,cv2.COLOR_BGR2LAB)
avg_a = np.average(result[:, :, 1])
avg_b = np.average(result[:, :, 2])
for x in range(result.shape[0]):
for y in range(result.shape[1]):
l, a, b = result[x, y, :]
l*=100/255.0
result[x,y,1] = a - (avg_a-128)*(1/100.0)*1.1
result[x,y,2] = a - (avg_b-128)*(1/100.0)*1.1
result = cv2.cvtColor(result,cv2.COLOR_LAB2BGR)
cv2.imshow('Enhanced Image',np.hstack([img,result]))
cv2.waitKey(0)
cv2.destroyWindow('Enhanced Image')
cv2.imwrite('result1.png',np.hstack([img,result]))
以下为代码运行结果:(左侧为原图,右侧为经过图像增强后的结果)
自动色彩均衡(Automatic Color Equalization,ACE)
ACE算法源自retinex算法,可以调整图像的对比度,实现人眼色彩恒常性和亮度恒常性,该算法考虑了图像中颜色和亮度的空间位置关系,进行局部特性的自适应滤波,实现具有局部和非线性特征的图像亮度与色彩调整和对比度调整,同时满足灰色世界理论假设和白色斑点假设。
ACE的增强效果普遍比retinex好。需要注意的是,ACE中当前像素是与整个图像的其他像素做差分比较,计算复杂度非常非常高,这也是限制它应用的最主要原因。所以,一般算法中,会通过指定采样数来代替与整副图像的像素点信息进行差分计算,减少运算量,提高效率。
以下是示例代码:
# 需在 Python 2 下运行
import cv2
import math
import numpy as np
def stretchImage(data, s=0.005, bins = 2000): #线性拉伸,去掉最大最小0.5%的像素值,然后线性拉伸至[0,1]
ht = np.histogram(data, bins);
d = np.cumsum(ht[0])/float(data.size)
lmin = 0; lmax=bins-1
while lmin<bins:
if d[lmin]>=s:
break
lmin+=1
while lmax>=0:
if d[lmax]<=1-s:
break
lmax-=1
return np.clip((data-ht[1][lmin])/(ht[1][lmax]-ht[1][lmin]), 0,1)
g_para = {}
def getPara(radius = 5): #根据半径计算权重参数矩阵
global g_para
m = g_para.get(radius, None)
if m is not None:
return m
size = radius*2+1
m = np.zeros((size, size))
for h in range(-radius, radius+1):
for w in range(-radius, radius+1):
if h==0 and w==0:
continue
m[radius+h, radius+w] = 1.0/math.sqrt(h**2+w**2)
m /= m.sum()
g_para[radius] = m
return m
def zmIce(I, ratio=4, radius=300): #常规的ACE实现
para = getPara(radius)
height,width = I.shape
zh,zw = [0]*radius + range(height) + [height-1]*radius, [0]*radius + range(width) + [width -1]*radius
Z = I[np.ix_(zh, zw)]
res = np.zeros(I.shape)
for h in range(radius*2+1):
for w in range(radius*2+1):
if para[h][w] == 0:
continue
res += (para[h][w] * np.clip((I-Z[h:h+height, w:w+width])*ratio, -1, 1))
return res
def zmIceFast(I, ratio, radius): #单通道ACE快速增强实现
height, width = I.shape[:2]
if min(height, width) <=2:
return np.zeros(I.shape)+0.5
Rs = cv2.resize(I, ((width+1)/2, (height+1)/2))
Rf = zmIceFast(Rs, ratio, radius) #递归调用
Rf = cv2.resize(Rf, (width, height))
Rs = cv2.resize(Rs, (width, height))
return Rf+zmIce(I,ratio, radius)-zmIce(Rs,ratio,radius)
def zmIceColor(I, ratio=4, radius=3): #rgb三通道分别增强,ratio是对比度增强因子,radius是卷积模板半径
res = np.zeros(I.shape)
for k in range(3):
res[:,:,k] = stretchImage(zmIceFast(I[:,:,k], ratio, radius))
return res
if __name__ == '__main__':
img = cv2.imread('test.jpg')
result = zmIceColor(img/255.0)*255
result = result.astype(np.uint8)
cv2.imshow('Enhanced Image',np.hstack([img,result]))
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('result.png', result)
以下为代码运行结果:(左侧为原图,右侧为经过图像增强后的结果)
待补充。
参考资料: