各大平台搜集后整理
项目地址:Image-Enhancement
一、直方图均衡化
① 算法原理
直方图均衡化,一般可用于灰度图像的对比增强(如:人脸阴影部位增强);
② 算法优缺点
如果直接对彩色图像 R,G,B
三通道分别均衡化后再合并,极容易出现颜色不均、失真等问题,所以,一般会将 RGB
图像转换到 YCrCb
空间,对 Y
通道进行均衡化(Y
通道代表亮度成分)

二、灰度世界算法
① 算法原理
灰度世界算法以灰度世界假设为基础,该假设认为:对于一幅有着大量色彩变化的图像,R,G,B
三个分量的平均值趋于同一灰度值 Gray
。从物理意义上讲,灰色世界法假设自然界景物对于光线的平均反射的均值在总体上是个定值,这个定值近似地为“灰色”。颜色平衡算法将这一假设强制应用于待处理图像,可以从图像中消除环境光的影响,获得原始场景图像。
一般有两种方法确定 Gray
值
1) 使用固定值,对于 8 位的图像 (0, 255) 通常取 128
作为灰度值
2) 计算增益系数,分别计算三通道的平均值 avgR,avgG,avgB,则:
A
v
g
=
(
a
v
g
R
+
a
v
g
G
+
a
v
g
B
)
/
3
Avg=(avgR + avgG + avgB) / 3
Avg=(avgR+avgG+avgB)/3
k
r
=
A
v
g
/
a
v
g
R
kr=Avg/avgR
kr=Avg/avgR
k
g
=
A
v
g
/
a
v
g
G
kg=Avg/avgG
kg=Avg/avgG
k
b
=
A
v
g
/
a
v
g
B
kb=Avg/avgB
kb=Avg/avgB
利用计算出的增益系数,重新计算每个像素值,构成新的图片。
② 算法优缺点
这种算法简单快速,但是当图像场景颜色并不丰富时,尤其出现大块单色物体时,该算法常会失效。
vegetable.png效果明显, sky.png效果不明显


三、Retinex算法
① 算法原理
视网膜-大脑皮层(Retinex)理论认为世界是无色的,人眼看到的世界是光与物质相互作用的结果,也就是说,映射到人眼中的图像和光的长波(R)、中波(G)、短波(B)以及物体的反射性质有关

I ( x , y ) = R ( x , y ) L ( x , y ) I(x, y)=R(x, y)L(x,y) I(x,y)=R(x,y)L(x,y)
其中 I I I 是人眼中看到的图像, R R R 是物体的反射分量, L L L 是环境光照射分量, ( x , y ) (x, y) (x,y) 是二维图像对应的位置
它通过估算
L
L
L 来计算
R
R
R,具体来说,
L
L
L 可以通过高斯模糊和
I
I
I 做卷积运算求得,用公式表示为:
l
o
g
(
R
)
=
l
o
g
(
I
)
−
l
o
g
(
L
)
log(R)=log(I)-log(L)
log(R)=log(I)−log(L)
L
=
G
∗
I
L=G*I
L=G∗I
其中 G G G 是高斯模糊的滤波器, ∗ * ∗ 表示卷积运算
G = 1 2 π σ e x p ( − r 2 σ 2 ) G=\frac{1}{\sqrt{2\pi}\sigma}exp(\frac{-r^2}{\sigma^2}) G=2πσ1exp(σ2−r2)
其中 σ \sigma σ 称为高斯周围空间常数(Gaussian Surround Space Constant),也就是算法中所谓的尺度,对图像处理有比较大的影响,对于二维图像, r 2 r^2 r2 等于对应位置即: x 2 + y 2 x^2+y^2 x2+y2,即一般认为光照分量是原图像经过高斯滤波后的结果。
MSR
:
l
o
g
(
R
)
=
l
o
g
(
R
)
+
W
e
i
g
h
t
(
i
)
∗
(
l
o
g
(
I
i
)
−
l
o
g
(
L
i
)
)
log(R) = log(R) + Weight(i) * (log(I_i) - log(L_i))
log(R)=log(R)+Weight(i)∗(log(Ii)−log(Li))
其中 Weight(i)
表示每个尺度对应的权重,要求各尺度权重之和必须为 1
,经典的取值为等权重。
R M S R = ∑ n = 1 N w n ( l o g ( I i ) − l o g ( I i ) ∗ G n ) R_{MSR} = \sum_{n=1}^{N} w_n(log(I_i)-log(I_i)*G_n) RMSR=n=1∑Nwn(log(Ii)−log(Ii)∗Gn)
上式中,I
为原始输入图像,G
是滤波函数,一般为高斯函数,N
为尺度的数量,W
为每个尺度的权重,一般都为 1/N
, R
表示在对数域的图像的输出。
② 算法优缺点
Retinex 算法,从 SSR
(单尺度Retinex)到 MSR
(多尺度Retinex)以及到最常用的 MSRCR
(带颜色恢复的多尺度 Retinex);其中色彩恢复主要目的是来调节由于图像局部区域对比度增强而导致颜色失真的缺陷
如果是灰度图像,只需要计算一次即可,如果是彩色图像,如 RGB
三通道,则每个通道均需要如上进行计算
先看一组公式:
R
M
S
R
C
R
(
x
,
y
)
′
=
G
⋅
R
M
S
R
C
R
(
x
,
y
)
+
b
{R_{MSRCR}(x,y)}^{'}=G⋅R_{MSRCR}(x,y)+b
RMSRCR(x,y)′=G⋅RMSRCR(x,y)+b
R
M
S
R
C
R
i
(
x
,
y
)
=
C
i
(
x
,
y
)
R
M
S
R
i
(
x
,
y
)
R_{MSRCR_i}(x,y)=C_i(x,y)R_{MSR_i}(x,y)
RMSRCRi(x,y)=Ci(x,y)RMSRi(x,y)
C
i
(
x
,
y
)
=
f
(
I
′
(
x
,
y
)
)
=
f
(
I
(
x
,
y
)
∑
j
=
1
N
I
j
(
x
,
y
)
)
C_i(x,y)=f(I^{'}(x,y))=f(\frac{I(x,y)}{\sum_{j=1}^{N}I_{j}(x,y)})
Ci(x,y)=f(I′(x,y))=f(∑j=1NIj(x,y)I(x,y))
f
(
I
′
(
x
,
y
)
)
=
β
l
o
g
(
α
I
′
(
x
,
y
)
)
=
β
l
o
g
(
α
I
′
(
x
,
y
)
)
−
l
o
g
(
∑
j
=
1
N
I
j
(
x
,
y
)
)
f(I^{'}(x,y))=βlog(αI^{'}(x,y))=β{log(αI^{'}(x,y))−log(\sum_{j=1}^{N} I_j(x,y))}
f(I′(x,y))=βlog(αI′(x,y))=βlog(αI′(x,y))−log(j=1∑NIj(x,y))
G
表示增益 Gain
(一般取值: 5
)
b
表示偏差 Offset
(一般取值: 25
)
I(x, y)
表示某个通道的图像
C
表示某个通道的彩色回复因子,用来调节3个通道颜色的比例;
f(·)
表示颜色空间的映射函数;
β
是增益常数(一般取值: 46
);
α
是受控制的非线性强度(一般取值:125
)
MSRCR
算法利用彩色恢复因子 C
,调节原始图像中3个颜色通道之间的比例关系,从而把相对较暗区域的信息凸显出来,达到了消除图像色彩失真的缺陷。 处理后的图像局部对比度提高,亮度与真实场景相似,在人们视觉感知下,图像显得更加逼真;但是 MSRCR
算法处理图像后,像素值一般会出现负值。所以从对数域 r(x, y)
转换为实数域 R(x, y)
后,需要通过改变增益 Gain
,偏差 Offset
对图像进行修正!

四、自动白平衡(AWB)
① 算法原理
用一个简单的概念来解释什么是白平衡:假设,图像中 R、G、B 最高灰度值对应于图像中的白点,最低灰度值的对应于图像中最暗的点;其余像素点利用 (ax+b)
映射函数把彩色图像中 R、G、B 三个通道内的像素灰度值映射到[0, 255]
的范围内.
白平衡的本质是让白色的物体在任何颜色的光源下都显示为白色,这一点对人眼来说很容易办到,因为人眼有自适应的能力,只要光源的色彩不超出一定的限度,就可以自动还原白色。但相机就不同了,无论是图像传感器还是胶卷都会记录光源的颜色,白色的物体就会带上光源的颜色,白平衡所要做的就是把这个偏色去掉。
② 算法优缺点
自动白平衡是一个很复杂的问题,目前还没有一个万能的方法可以解决所有场景的白平衡问题!

五、自动色彩均衡(ACE)
① 算法原理
ACE 算法源自 retinex 算法,可以调整图像的对比度,实现人眼色彩恒常性和亮度恒常性,该算法考虑了图像中颜色和亮度的空间位置关系,进行局部特性的自适应滤波,实现具有局部和非线性特征的图像亮度与色彩调整和对比度调整,同时满足灰色世界理论假设和白色斑点假设。
第一步:对图像进行色彩/空域调整,完成图像的色差校正,得到空域重构图像;
R c ( p ) = ∑ j ∈ S u b s e t , j ≠ p r ( I c ( p ) − I c ( j ) ) d ( p , j ) R_c(p)=\sum_{j\in Subset,j\ne p}\frac{r(I_c(p)-I_c(j))}{d(p,j)} Rc(p)=j∈Subset,j=p∑d(p,j)r(Ic(p)−Ic(j))
式中, R c Rc Rc 是中间结果, I c ( p ) − I c ( j ) I_c(p)-I_c(j) Ic(p)−Ic(j) 为两个不同点的亮度差, d ( p , j ) d(p,j) d(p,j) 表示距离度量函数, r ( ∗ ) r(*) r(∗) 为亮度表现函数,需是奇函数;这一步可以适应局部图像对比度, r ( ∗ ) r(*) r(∗) 能够放大较小的差异,并丰富大的差异,根据局部内容扩展或者压缩动态范围。一般得, r ( ∗ ) r(*) r(∗) 为:
r ( x ) = { 1 , x < − T x / T , − T ⩽ x ⩽ T − 1 , x > T r(x)=\begin{cases} 1&,x<-T \\ x/T&,-T\leqslant x\leqslant T \\ -1&,x>T\end{cases} r(x)=⎩ ⎨ ⎧1x/T−1,x<−T,−T⩽x⩽T,x>T
第二步:对校正后的图像进行动态扩展。ACE算法是对单一色道进行的,对于彩色图片需要对每一个色道分别处理。
其中存在一种简单的线性扩展:
R ( x ) = r o u n d [ 127.5 + w ∗ R c ( p ) ] R(x)=round[127.5+w*R_c(p)] R(x)=round[127.5+w∗Rc(p)]
其中, w w w 表示线段 [ ( 0 , m c ) , ( 255 , M c ) ] [(0,m_c),(255,M_c)] [(0,mc),(255,Mc)] 的斜率,且有: M c = m i n [ R c ( p ) ] , M c = m a x [ R c ( p ) ] M_c=min[R_c(p)],M_c=max[R_c(p)] Mc=min[Rc(p)],Mc=max[Rc(p)]
第三步:利用下面的公式将 R ( x ) R(x) R(x) 展到 [ 0 , 1 ] [0,1] [0,1] 之间,得到增强后的通道。
L ( x ) = R ( x ) − m i n R m a x R − m i n R L(x)=\frac{R(x)-minR}{maxR-minR} L(x)=maxR−minRR(x)−minR
②算法优缺点
ACE 的增强效果普遍比 retinex 好。需要注意的是,在 ACE 中,当前像素是与整个图像的其他像素做差分比较,计算复杂度非常非常高,这也是限制它应用的最主要原因。
所以,一般算法中,会通过指定采样数来代替与整副图像的像素点信息进行差分计算,减少运算量,提高效率。

六、总结
查看各种传统算法的效果图,ACE自动色彩均衡算法具有比较好的普遍性和效果,当然,对于一些图片ACE也不能得到很好地效果
部分实现代码
# 部分图像增强算法代码
"""
Project :Image-Enhancement
File :base_enhance.py
Author :MangoloD
Date :2022/3/9 13:48
"""
# 图像增强算法,图像锐化算法
# 1)基于直方图均衡化 2)基于拉普拉斯算子 3)基于对数变换 4)基于伽马变换 5)CLAHE 6)retinex-SSR 7)retinex-MSR
# 其中,基于拉普拉斯算子的图像增强为利用空域卷积运算实现滤波
# 基于同一图像对比增强效果
# 直方图均衡化:对比度较低的图像适合使用直方图均衡化方法来增强图像细节
# 拉普拉斯算子可以增强局部的图像对比度
# log对数变换对于整体对比度偏低并且灰度值偏低的图像增强效果较好
# 伽马变换对于图像对比度偏低,并且整体亮度值偏高(对于相机过曝)情况下的图像增强效果明显
import cv2
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 直方图均衡增强
def hist(image):
r, g, b = cv2.split(image)
r1 = cv2.equalizeHist(r)
g1 = cv2.equalizeHist(g)
b1 = cv2.equalizeHist(b)
image_equal_clo = cv2.merge([r1, g1, b1])
return image_equal_clo
# 拉普拉斯算子
def laplacian(image):
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
image_lap = cv2.filter2D(image, cv2.CV_8UC3, kernel)
return image_lap
# 对数变换
def log(image):
image_log = np.uint8(np.log(np.array(image) + 1))
cv2.normalize(image_log, image_log, 0, 255, cv2.NORM_MINMAX)
# 转换成8bit图像显示
cv2.convertScaleAbs(image_log, image_log)
return image_log
# 伽马变换
def gamma(image):
fgamma = 2
image_gamma = np.uint8(np.power((np.array(image) / 255.0), fgamma) * 255.0)
cv2.normalize(image_gamma, image_gamma, 0, 255, cv2.NORM_MINMAX)
cv2.convertScaleAbs(image_gamma, image_gamma)
return image_gamma
# 限制对比度自适应直方图均衡化CLAHE
def clahe(image):
b, g, r = cv2.split(image)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
b = clahe.apply(b)
g = clahe.apply(g)
r = clahe.apply(r)
image_clahe = cv2.merge([b, g, r])
return image_clahe
def replaceZeroes(data):
min_nonzero = min(data[np.nonzero(data)])
data[data == 0] = min_nonzero
return data
# retinex SSR
def SSR(src_img, size):
L_blur = cv2.GaussianBlur(src_img, (size, size), 0)
img = replaceZeroes(src_img)
L_blur = replaceZeroes(L_blur)
dst_Img = cv2.log(img / 255.0)
dst_Lblur = cv2.log(L_blur / 255.0)
dst_IxL = cv2.multiply(dst_Img, dst_Lblur)
log_R = cv2.subtract(dst_Img, dst_IxL)
dst_R = cv2.normalize(log_R, None, 0, 255, cv2.NORM_MINMAX)
log_uint8 = cv2.convertScaleAbs(dst_R)
return log_uint8
def SSR_image(image):
size = 3
b_gray, g_gray, r_gray = cv2.split(image)
b_gray = SSR(b_gray, size)
g_gray = SSR(g_gray, size)
r_gray = SSR(r_gray, size)
result = cv2.merge([b_gray, g_gray, r_gray])
return result
# retinex MMR
def MSR(img, scales):
weight = 1 / 3.0
scales_size = len(scales)
h, w = img.shape[:2]
log_R = np.zeros((h, w), dtype=np.float32)
for i in range(scales_size):
img = replaceZeroes(img)
L_blur = cv2.GaussianBlur(img, (scales[i], scales[i]), 0)
L_blur = replaceZeroes(L_blur)
dst_Img = cv2.log(img / 255.0)
dst_Lblur = cv2.log(L_blur / 255.0)
dst_Ixl = cv2.multiply(dst_Img, dst_Lblur)
log_R += weight * cv2.subtract(dst_Img, dst_Ixl)
dst_R = cv2.normalize(log_R, None, 0, 255, cv2.NORM_MINMAX)
log_uint8 = cv2.convertScaleAbs(dst_R)
return log_uint8
def MSR_image(image):
scales = [15, 101, 301] # [3,5,9]
b_gray, g_gray, r_gray = cv2.split(image)
b_gray = MSR(b_gray, scales)
g_gray = MSR(g_gray, scales)
r_gray = MSR(r_gray, scales)
result = cv2.merge([b_gray, g_gray, r_gray])
return result
def image_enhance(image, is_gamma=False):
if is_gamma:
image = image / 255.0 # 注意255.0得采用浮点数
image = np.power(image, 0.5) * 255.0
image = image.astype(np.uint8)
# numpy实现
out_min = 0
out_max = 255
in_min = np.min(image)
in_max = np.max(image)
a = float(out_max - out_min) / (in_max - in_min)
b = out_min - a * in_min
img_norm = image * a + b
img_norm = img_norm.astype(np.uint8)
return img_norm
def paint(image):
plt.subplot(4, 2, 1)
plt.imshow(image)
plt.axis('off')
plt.title('Offical')
# 直方图均衡增强
image_equal_clo = hist(image)
plt.subplot(4, 2, 2)
plt.imshow(image_equal_clo)
plt.axis('off')
plt.title('equal_enhance')
# 拉普拉斯算法增强
image_lap = laplacian(image)
plt.subplot(4, 2, 3)
plt.imshow(image_lap)
plt.axis('off')
plt.title('laplacian_enhance')
# LoG对象算法增强
image_log = log(image)
plt.subplot(4, 2, 4)
plt.imshow(image_log)
plt.axis('off')
plt.title('log_enhance')
# 伽马变换
image_gamma = gamma(image)
plt.subplot(4, 2, 5)
plt.imshow(image_gamma)
plt.axis('off')
plt.title('gamma_enhance')
# CLAHE
image_clahe = clahe(image)
plt.subplot(4, 2, 6)
plt.imshow(image_clahe)
plt.axis('off')
plt.title('CLAHE')
# retinex_ssr
image_ssr = SSR_image(image)
plt.subplot(4, 2, 7)
plt.imshow(image_ssr)
plt.axis('off')
plt.title('SSR')
# retinex_msr
image_msr = MSR_image(image)
plt.subplot(4, 2, 8)
plt.imshow(image_msr)
plt.axis('off')
plt.title('MSR')
plt.show()
if __name__ == "__main__":
image = cv2.imread("images/BGRT2.jpg")
image_ = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
flag = 0
if flag == 0:
paint(image_)
elif flag == 1:
image_msr = MSR_image(image)
plt.subplot(1, 2, 1)
plt.imshow(image_)
plt.axis('off')
plt.title('Offical')
plt.subplot(1, 2, 2)
plt.imshow(cv2.cvtColor(image_msr, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.title('MSR')
plt.show()
else:
img = image_enhance(image_, is_gamma=False)
plt.subplot(1, 2, 1)
plt.imshow(image_)
plt.axis('off')
plt.title('Offical')
plt.subplot(1, 2, 2)
plt.imshow(img)
plt.axis('off')
plt.title('common')
plt.show()