【图像增强】常见的图像增强算法

各大平台搜集后整理

项目地址: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 k r = A v g / a v g R k g = A v g / a v g G k b = A v g / a v g B Avg=(avgR + avgG + avgB) / 3 \\ kr=Avg/avgR \\ kg=Avg/avgG \\ kb=Avg/avgB Avg=(avgR+avgG+avgB)/3kr=Avg/avgRkg=Avg/avgGkb=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是人眼中看到的图像,R是物体的反射分量,L是环境光照射分量,(x, y)是二维图像对应的位置

它通过估算L来计算R,具体来说,L可以通过高斯模糊和I做卷积运算求得,用公式表示为:
l o g ( R ) = l o g ( I ) − l o g ( L ) L = F ∗ I log(R)=log(I)-log(L)\\L=F*I log(R)=log(I)log(L)L=FI
其中 F F F是高斯模糊的滤波器, ∗ * 表示卷积运算
F = 1 2 π σ e x p ( − r 2 σ 2 ) F=\frac{1}{\sqrt{2\pi}\sigma}exp(\frac{-r^2}{\sigma^2}) F=2π σ1exp(σ2r2)
其中 σ \sigma σ 称为高斯周围空间常数(Gaussian Surround Space Constant),也就是算法中所谓的尺度,对图像处理有比较大的影响,对于二维图像, r 2 r^2 r2 等于对应位置即: x 2 + y 2 x^2+y^2 x2+y2,即一般认为光照分量是原图像经过高斯滤波后的结果

② 算法优缺点
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 M S R C R ( x , y ) = C ( x , y ) R M S R ( x , y ) C ( x , y ) = f [ I ′ ( x , y ) ] = f [ I ( x , y ) ∑ I ( x , y ) ] C i ( x , y ) = f [ I i ′ ( x , y ) ] = f [ I i ( x , y ) ∑ j = 1 N I j ( x , y ) ] f [ I ′ ( x , y ) ] = β l o g [ α I ′ ( x , y ) ] = β l o g [ α I ′ ( x , y ) ] − l o g [ ∑ I ( x , y ) ] RMSRCR(x,y)'=G⋅RMSRCR(x,y)+b \\ RMSRCR (x,y)=C(x,y)RMSR(x,y) \\ C(x,y)=f[I'(x,y)]=f[\frac{I(x,y)}{∑I(x,y)}]Ci(x,y)=f[Ii′(x,y)]=f[Ii(x,y)∑j=1NIj(x,y)] \\ f[I'(x,y)]=βlog[αI'(x,y)]=β{log[αI'(x,y)]−log[∑I(x,y)]} RMSRCR(x,y)=GRMSRCR(x,y)+bRMSRCR(x,y)=C(x,y)RMSR(x,y)C(x,y)=f[I(x,y)]=f[I(x,y)I(x,y)]Ci(x,y)=f[Ii(x,y)]=f[Ii(x,y)j=1NIj(x,y)]f[I(x,y)]=βlog[αI(x,y)]=βlog[αI(x,y)]log[I(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)=jSubset,j=pd(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/T1,x<T,TxT,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+wRc(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)=maxRminRR(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()

猜你喜欢

转载自blog.csdn.net/weixin_42166222/article/details/123377594