传统低光图像增强方法

前言


前言

        随着信息时代的到来,多媒体技术已经进入千家万户,视频图像作为感知世界的重要载体,已经成为人们不可或缺的信息资源。然而受到成像设备和照明条件限制,图像视频捕获过程中,由黑暗环境下带来的低对比度和成像设备带来的噪声往往极大限制了图片的质量,从而造成信息损失,同时降低人的感观体验,低光的照明环境同时也影响着计算机下游任务如(目标检测,人脸识别,语义分割)等,人的感知系统很难在有限的光照下捕获到图片的有效信息,在计算机视觉中,图像是三维的矩阵数据信息,如何捕获这些矩阵在数值上的分布和差异是反映图像信息的关键,通过有效调整矩阵数据的数值分布,是现有低光图像增强的原理和方法。


        低光图像增强是计算机视觉领域中的一个重要研究内容,其目的是提高低光图像的亮度、对比度和视觉效果,传统的低光图像增强方法可以分为基于直方图均衡化(HE),伽马变换Retinex分解理论的传统方法。

一、直方图均衡化

       直方图均衡化是一种基于图像像素灰度值统计特性的增强方法。它的基本思想是通过调整图像的灰度直方图,使图像的灰度分布更加均匀。对于低光图像,其灰度直方图通常集中在较暗的区域,通过 HE 可以拉伸灰度范围,从而提高图像的对比度,如下介绍几种比较常见的均衡化方法。

1.1 CLAHE

        当图像呈现出广泛的对比度差异时,传统的直方图均衡化方法通常难以产生令人满意的结果。在此情况下,限制对比度自适应直方图均衡化(CLAHE)方法可以一定程度上解决这一问题。该方法将图像划分成若干小块,针对每个小块分别进行直方图均衡化操作。并且,在均衡化的过程中,它会对对比度增强的幅度加以限制。这样一来,既能够避免噪声或细节被过度增强,又能显著提升图像的视觉质量

import cv2
import matplotlib.pyplot as plt

def CLAHE(image):
    # 以彩色模式读取图像(cv2.IMREAD_COLOR表示读取彩色图像)
    image = cv2.imread(image, cv2.IMREAD_COLOR)

    if image is None:
        print('Unable to load input_image!')
        return
    else:
        # 将图像从BGR色彩空间转换为RGB色彩空间(因为matplotlib默认显示RGB图像)
        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

        # 创建CLAHE对象,这里的参数设置可根据实际需求调整
        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        # 对彩色图像的每个通道分别应用CLAHE处理
        channels = cv2.split(image_rgb)
        clahe_channels = []
        for channel in channels:
            clahe_channel = clahe.apply(channel)
            clahe_channels.append(clahe_channel)
        # 合并处理后的通道,重新得到彩色图像
        clahe_image_rgb = cv2.merge(clahe_channels)

        plt.figure(figsize=(6, 4))
        plt.subplot(121), plt.title('Original image'), plt.axis('off')
        plt.imshow(image_rgb)
        plt.subplot(122), plt.title('Clahe image'), plt.axis('off')
        plt.imshow(clahe_image_rgb)
        plt.tight_layout()
        plt.show()


imgfile1 = './images/hohai.png'
CLAHE(imgfile1)

1.2 BBHE

        BBHE 算法即亮度保持双直方图均衡化算法,是一种用于图像增强的方法,主要目的是在增强图像对比度的同时保持图像的平均亮度。首先计算输入图像的平均灰度值,将图像的灰度直方图以平均灰度值为阈值,分割成两个子直方图,一个包含小于等于平均灰度值的像素,另一个包含大于平均灰度值的像素.然后分别对两个子直方图进行均衡化处理,均衡化后的子图像在平均亮度上相互约束,从而达到保持图像整体平均亮度的效果。

import cv2
import numpy as np


def BBHE(image):
    # 这里不再重复将传入的图像转换为灰度图了,因为传入的本身就是单通道灰度图
    # 直接计算图像的平均灰度值
    mean_value = np.mean(image)
    # 根据平均灰度值分割图像
    low_mask = image <= mean_value
    high_mask = image > mean_value
    low_img = image[low_mask]
    high_img = image[high_mask]
    # 对两个子图像分别进行直方图均衡化
    equalized_low = cv2.equalizeHist(low_img)
    equalized_high = cv2.equalizeHist(high_img)
    # 创建与原始图像大小相同的零数组
    equalized_img = np.zeros_like(image)
    # 将均衡化后的子图像合并到结果图像中
    equalized_img[low_mask] = equalized_low.flatten()
    equalized_img[high_mask] = equalized_high.flatten()
    return equalized_img


def BBHE_color(image):
    # 分离彩色图像的B、G、R三个通道
    b, g, r = cv2.split(image)
    # 对蓝色通道应用BBHE算法,此时传入的b本身就是单通道灰度图,无需再转换
    equalized_b = BBHE(b)
    # 对绿色通道应用BBHE算法
    equalized_g = BBHE(g)
    # 对红色通道应用BBHE算法
    equalized_r = BBHE(r)
    # 合并处理后的三个通道,形成彩色图像
    equalized_image = cv2.merge([equalized_b, equalized_g, equalized_r])
    return equalized_image


# 读取图像
image = cv2.imread('./images/hohai.png')
# 应用BBHE_color算法处理彩色图像
result = BBHE_color(image)
# 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('BBHE Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.3 AIEBHE

        AIEBHE 算法首先将图像的灰度直方图划分为两个子直方图。通常,以图像的平均灰度值为界,将灰度值小于等于平均灰度值的像素构成一个子直方图,灰度值大于平均灰度值的像素构成另一个子直方图。对于每个子直方图,应用自适应的指数映射函数,在进行指数映射后,对两个子直方图分别进行类似于传统直方图均衡化的操作,最后,将经过处理的两个子直方图对应的像素区域合并起来,形成最终的增强图像。

import cv2
import numpy as np


def AIEBHE(image):
    # 如果是彩色图像,分离通道
    if len(image.shape) == 3:
        b, g, r = cv2.split(image)
        # 对蓝色通道应用AIEBHE算法
        enhanced_b = AIEBHE_single_channel(b)
        # 对绿色通道应用AIEBHE算法
        enhanced_g = AIEBHE_single_channel(g)
        # 对红色通道应用AIEBHE算法
        enhanced_r = AIEBHE_single_channel(r)
        # 合并处理后的通道,形成彩色图像
        enhanced_image = cv2.merge([enhanced_b, enhanced_g, enhanced_r])
        return enhanced_image
    else:
        return AIEBHE_single_channel(image)


def AIEBHE_single_channel(channel_image):
    # 计算图像的平均灰度值(对于单通道图像来说)
    mean_value = np.mean(channel_image)
    # 构建两个子直方图
    low_mask = channel_image <= mean_value
    high_mask = channel_image > mean_value
    low_image = channel_image[low_mask]
    high_image = channel_image[high_mask]
    # 计算子直方图的累积分布函数(CDF)
    cdf_low = np.cumsum(np.histogram(low_image, bins=256)[0])
    cdf_high = np.cumsum(np.histogram(high_image, bins=256)[0])
    # 归一化累积分布函数
    cdf_low_normalized = cdf_low / cdf_low[-1]
    cdf_high_normalized = cdf_high / cdf_high[-1]
    # 自适应参数(这里可以根据实际情况调整)
    a_low = 200
    b_low = 5
    a_high = 200
    b_high = 5
    # 自适应指数映射
    exp_mapped_low = a_low * (1 - np.exp(-b_low * cdf_low_normalized))
    exp_mapped_high = a_high * (1 - np.exp(-b_high * cdf_high_normalized))
    # 构建映射表
    mapping_table_low = np.round(exp_mapped_low).astype(np.uint8)
    mapping_table_high = np.round(exp_mapped_high).astype(np.uint8)
    # 应用映射表进行直方图均衡化
    equalized_low = mapping_table_low[low_image]
    equalized_high = mapping_table_high[high_image]
    # 创建与原始图像大小相同的零数组用于存储增强后的图像
    enhanced_image = np.zeros_like(channel_image)
    # 将均衡化后的子图像合并
    enhanced_image[low_mask] = equalized_low
    enhanced_image[high_mask] = equalized_high
    return enhanced_image


# 读取图像
image = cv2.imread('./images/hohai.png')
# 应用AIEBHE算法
result = AIEBHE(image)
# 显示原始图像和增强后的图像
cv2.imshow('Original Image', image)
cv2.imshow('AIEBHE Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

        基于 HE 的这些低光图像增强算法在改善低光图像质量方面各有特点,总体来说都是改变图像的像数值分布来增强图像,但是效果可能不佳,并且泛化能力差,其方法原理可以借鉴学习,在一些简单的场景也许有应用市场。


二、伽马变换

        在低照度图像增强中,伽马变换的原理是通过对图像的灰度值进行非线性变换,以提高图像的对比度和清晰度。在低照度条件下,图像的亮度可能较低,细节不够清晰。通过调整伽马值,可以改变图像的对比度和亮度分布。对于曝光不足或过度曝光的图像,伽马变换可以使其细节更加清晰,提升图像的整体质量。

import numpy as np
import matplotlib.pyplot as plt
import cv2
 
img = cv2.imread('./images/hohai.png')
img = img.astype(np.float32) / 255.0
 
def gamma_correction(img, gamma):
    return np.power(img, gamma)
 
gamma = 0.5
img_gamma = gamma_correction(img, gamma)
 
plt.subplot(1, 2, 1)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('原图像', fontdict={'family': 'KaiTi', 'size': 10})
 
plt.subplot(1, 2, 2)
plt.imshow(cv2.cvtColor(img_gamma, cv2.COLOR_BGR2RGB))
plt.title('伽马变换后图像', fontdict={'family': 'KaiTi', 'size': 10})
plt.show()
 
cv2.imwrite("image.jpg", img_gamma * 255)  # 保存伽马变换后的图像

三、Rentinex 分解

        Retinex 理论基础:该理论认为人眼感知到的物体颜色和亮度由物体表面的反射属性(反射率)以及照射到物体表面的光线(照度)共同决定。也就是说,一幅图像可以看作是由反射分量和光照分量相乘得到的,即图像I(x,y)=R(x,y)×L(x,y) ,其中R(x,y)表示观测到的图像, 是反射率分量包含物体的本质特征信息,相对稳定且变化缓慢,L(x,y) 是光照分量通常变化较快且在空间上具有不均匀性。基于 Retinex 分解的图像增强方法就是要从给定的图像中分离出这两个分量,然后对光照分量进行调整,以达到增强图像的目的

3.1 单尺度的Retinex(SSR)算法

        选择一个合适的高斯卷积核G(x,y,σ),其中σ为尺度参数,用于模拟人眼对照度的感知特性,对输入图像I(x,y)进行卷积运算,得到光照估计值再根据Retinex理论,计算反射分量不过实际应用中为避免除零等问题以及使结果更符合视觉感知,通常会进行一些改进和归一化处理,比如对结果进行限幅、拉伸等操作,最终得到增强后的图像。

# SSR
import cv2
import numpy as np
 
 
def replaceZeroes(data):
    min_nonzero = np.min(data[np.nonzero(data)])  # 找到数组中最小的非零值
    data = np.where(data == 0, min_nonzero, data)  # 将数组中的零值替换为最小的非零值
    return data  # 返回替换后的数组
 
def SSR(src_img, size):
    L_blur = cv2.GaussianBlur(src_img, (size, size), 0)  # 高斯函数
    img = replaceZeroes(src_img)  # 去除0  
    L_blur = replaceZeroes(L_blur)  # 去除0
 
    dst_Img = cv2.log(img / 255.0)  # 归一化取log
    dst_Lblur = cv2.log(L_blur / 255.0)  # 归一化取log
    dst_IxL = cv2.multiply(dst_Img, dst_Lblur)  # 乘  L(x,y)=S(x,y)*G(x,y)
    log_R = cv2.subtract(dst_Img, dst_IxL)  # 减  log(R(x,y))=log(S(x,y))-log(L(x,y))
 
    dst_R = cv2.normalize(log_R, None, 0, 255, cv2.NORM_MINMAX)  # 放缩到0-255
    log_uint8 = cv2.convertScaleAbs(dst_R)  # 取整
    return log_uint8
 
 
def SSR_image(image):
    size = 3
    b_gray, g_gray, r_gray = cv2.split(image)  # 拆分三个通道
    # 分别对每一个通道进行 SSR
    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
 
 
if __name__ == "__main__":
    input_img = cv2.imread('./images/hohai.png', cv2.IMREAD_COLOR)  # 读取输入图像
    enhanced_img = SSR_image(input_img)  # 调用 SSR 函数得到增强后的图像
    cv2.imwrite('./images/retinexresults/hohai.png', enhanced_img)  # 将增强后的图像保存为 img_2.png
    # 显示原始图像和增强后的图像
    cv2.imshow('Original Image', input_img)
    cv2.imshow('Enhanced(SSR) Image', enhanced_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

3.2 MSRCR 具有色彩恢复的多尺度Retinex算法

        在经过 Retinex 处理后,图像的颜色可能会出现偏差,需要进行颜色恢复操作颜色恢复,最终增强的图像MSRCR 算法通过多尺度 Retinex 处理来增强图像的对比度,去除光照不均的影响,并通过颜色恢复步骤来保持图像的自然色彩,从而得到视觉效果较好的增强图像

import cv2
import numpy as np
import math
 
 
def replaceZeroes(data):
    min_nonzero = min(data[np.nonzero(data)])
    data[data == 0] = min_nonzero
    return data
 
 
def simple_color_balance(input_img, s1, s2):
    h, w = input_img.shape[:2]
    out_img = np.zeros([h, w])
    sort_img = input_img.copy()
    one_dim_array = sort_img.flatten()  # 转化为一维数组
    sort_array = sorted(one_dim_array)  # 对一维数组按升序排序
 
    per1 = int((h * w) * s1 / 100)
    minvalue = sort_array[per1]
 
    per2 = int((h * w) * s2 / 100)
    maxvalue = sort_array[(h * w) - 1 - per2]
 
    # 实施简单白平衡算法
    if (maxvalue <= minvalue):
        for i in range(h):
            for j in range(w):
                out_img[i, j] = maxvalue
    else:
        scale = 255.0 / (maxvalue - minvalue)
        for m in range(h):
            for n in range(w):
                if (input_img[m, n] < minvalue):
                    out_img[m, n] = 0
                elif (input_img[m, n] > maxvalue):
                    out_img[m, n] = 255
                else:
                    out_img[m, n] = scale * (input_img[m, n] - minvalue)  # 映射中间段的图像像素
 
    out_img = cv2.convertScaleAbs(out_img)
    return out_img
 
 
def MSRCR(img, scales, s1, s2):
    h, w = img.shape[:2]
    # print(h, w)
    scles_size = len(scales)
    img = np.array(img, dtype=np.float64)
    # print(img)
    log_R = np.zeros((h, w), dtype=np.float64)
    img_sum = np.add(img[:, :, 0], img[:, :, 1], img[:, :, 2])
    img_sum = replaceZeroes(img_sum)
    gray_img = []
 
    for j in range(3):
        img[:, :, j] = replaceZeroes(img[:, :, j])
        for i in range(0, scles_size):
            L_blur = cv2.GaussianBlur(img[:, :, j], (scales[i], scales[i]), 0)
            L_blur = replaceZeroes(L_blur)
 
            dst_img = cv2.log(img[:, :, j])
            dst_Lblur = cv2.log(L_blur)
            log_R += cv2.subtract(dst_img, dst_Lblur)
        MSR = log_R / 3.0
        '''
            img_sum_log = np.zeros((h, w))
            for i in range(0, h):
                for k in range(0, w):
                    img_sum_log[i,k] = 125.0*math.log(img[i,k,j]) - math.log(img_sum[i,k])
            MSRCR = MSR * (img_sum_log[:, :])
            print(img_sum)
            # x = cv2.log(img_sum)
            '''
        MSRCR = MSR * (cv2.log(125.0 * img[:, :, j]) - cv2.log(img_sum))
        gray = simple_color_balance(MSRCR, s1, s2)
        gray_img.append(gray)
 
    return gray_img
 
 
if __name__ == '__main__':
    scales = [15, 101, 301]
    s1, s2 = 2, 3
    src_img = cv2.imread('./images/hohai.png')
    src_img = cv2.cvtColor(src_img, cv2.COLOR_BGR2RGB)
    cv2.imshow('Original Image', src_img)
    MSRCR_Out = MSRCR(src_img, scales, s1, s2)
 
    result = cv2.merge([MSRCR_Out[0], MSRCR_Out[1], MSRCR_Out[2]])
    cv2.imwrite('./images/retinexresults/MSRCR.png', result)  # 将增强后的图像保存为 img_2.png
    cv2.imshow('Enhanced(MSRCR) Image', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

3.3 BIE

BIE是一种受生物视觉机制启发的图像增强框架,用于低动态范围(LDR)图像增强和高动态范围(HDR)图像色调映射任务,以提高图像细节的可见度和场景的可视性

1、图像分离:将输入图像分离为两条视觉通路:结构通路和细节通路。

2、图像增强:采用扩展的生物归一化模型,将全局和局部亮度自适应相结合

3、细节增强和局部噪声抑制

4、综合结构路径和细节路径的输出,实现微光图像增强。

        基于Rentinex方法的低光图像增强的关键在于将这两个分量从图像中分离出来,之后对光照分量做合理的调整,再重新组合得到增强后的图像。单尺度 Retinex 算法较为简单直接,不过容易出现颜色失真、细节还原欠佳的情况;多尺度 Retinex 算法结合了不同尺度的信息,在保留细节以及色彩还原方面表现更好,但相应地计算量会有所增加。总体而言,基于 Retinex 理论的方法为低光图像增强提供了一种从图像物理构成角度出发的有效思路,在提升图像质量、凸显暗部细节等方面有着积极作用,不过不同的具体算法在实际应用中各有其优势与不足,需根据具体情况选用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值