Retinex视网膜算法
Retinex算法模拟人类视觉系统对光照和反射的处理机制,核心是将图像分解为光照分量(Luminance)和反射分量(Reflectance) ,公式为:
I(x,y)=R(x,y)×L(x,y) I(x,y) = R(x,y) \times L(x,y) I(x,y)=R(x,y)×L(x,y)
通过对数变换转为加法模型(便于分离分量):
log(I(x,y))=log(R(x,y))+log(L(x,y)) \log(I(x,y)) = \log(R(x,y)) + \log(L(x,y)) log(I(x,y))=log(R(x,y))+log(L(x,y))
以下是 SSR、MSR、MSRCR 的原理与区别:
1. 单尺度 Retinex(SSR, Single - Scale Retinex)
核心思想 :用单个高斯核估计光照分量,分离反射分量实现增强。
步骤:
-
对数变换 :将图像转对数空间,拆分光照和反射的加法关系:
log(I)=log(R)+log(L) \log(I) = \log(R) + \log(L) log(I)=log(R)+log(L) -
高斯滤波估计光照 :
用高斯核 ( G_{\sigma} ) 对对数图像卷积,模拟缓慢变化的光照:
log(L)≈Gσ∗log(I) \log(L) \approx G_{\sigma} * \log(I) log(L)≈Gσ∗log(I)(( * ) 表示卷积,( \sigma ) 是高斯核标准差,控制光照平滑程度)
-
提取反射分量 :
反射分量的对数为原始对数图像减去光照对数:
log(R)=log(I)−log(L) \log(R) = \log(I) - \log(L) log(R)=log(I)−log(L) -
指数变换还原 :
将反射分量转回线性空间:
R=exp(log(R)) R = \exp(\log(R)) R=exp(log(R)) -
归一化:映射到 0 - 255 范围,输出增强图像。
特点:
- 优点:计算简单,适合增强局部细节。
- 缺点 :仅用一个尺度,易出现过度增强(小 ( \sigma ))或细节丢失(大 ( \sigma )),对不同场景适应性弱。
代码实现
python
import cv2
import numpy as np
import matplotlib.pyplot as plt
def single_scale_retinex(img, sigma=128, normalize=True):
"""
SSR算法实现
:param img: 输入图像 (BGR格式)
:param sigma: 高斯核标准差 (控制光照估计尺度)
:param normalize: 是否进行结果归一化
:return: 增强后的图像
"""
# 转换为浮点型并加1避免log(0)
img = img.astype(np.float32) / 255.0 + 1e-6
# 分别处理每个通道
channels = []
for ch in range(3):
img_ch = img[:, :, ch]
# 步骤1: 高斯模糊估计光照分量
gaussian = cv2.GaussianBlur(
src=img_ch,
ksize=(0, 0), # 自动根据sigma计算核大小
sigmaX=sigma,
sigmaY=sigma
)
# 步骤2: 对数域减法分离反射分量
log_img = np.log(img_ch)
log_blur = np.log(gaussian)
retinex = log_img - log_blur
channels.append(retinex)
# 合并通道
result = np.stack(channels, axis=2)
# 可选归一化 (增强视觉效果)
if normalize:
result = (result - np.min(result)) / (np.max(result) - np.min(result))
result = (result * 255).astype(np.uint8)
return result
# 示例使用
if __name__ == "__main__":
# 读取图像
image = cv2.imread('img_1.png') # 替换为你的图像路径
# 应用SSR
ssr_result = single_scale_retinex(image, sigma=100,normalize=True)
cv2.imwrite('enhanced_image.png', ssr_result)
# 显示结果
plt.figure(figsize=(12, 6))
plt.subplot(121)
plt.title("Original Image")
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.subplot(122)
plt.title("SSR Enhanced")
plt.imshow(cv2.cvtColor(ssr_result, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.tight_layout()
plt.savefig('ssr_result.jpg', dpi=300)
plt.show()
结果图像
输入图像:
增强图像:
2. 多尺度 Retinex(MSR, Multi - Scale Retinex)
核心思想 :融合多个不同尺度的 SSR 结果,平衡全局与局部增强。
步骤:
-
多尺度 SSR 计算 :
用一组不同 sigmasigmasigma 的高斯核(如sigma1sigma1sigma1,sigma2sigma2sigma2,sigma3sigma3sigma3),分别计算单尺度 Retinex:
MSR=1N∑i=1N[log(I)−log(Gσi∗I)] MSR = \frac{1}{N} \sum_{i=1}^N \left[ \log(I) - \log\left(G_{\sigma_i} * I\right) \right] MSR=N1i=1∑N[log(I)−log(Gσi∗I)](( N ) 是尺度数量,通常取 3 - 5 个尺度覆盖不同频率)
-
直接输出或后处理 :
多尺度结果已平衡全局光照和局部细节,可直接归一化输出。
特点:
- 优点:比 SSR 更鲁棒,兼顾大尺度(保留整体对比度)和小尺度(增强细节)。
- 缺点:未显式处理颜色失真,易出现色偏;仅优化对比度,未针对性恢复颜色。
代码实现
python
import cv2
import numpy as np
import matplotlib.pyplot as plt
def multi_scale_retinex(img, sigma_list=[15, 80, 250], weights=None, normalize=True):
"""
MSR算法实现
:param img: 输入图像 (BGR格式)
:param sigma_list: 高斯核标准差列表,定义不同尺度
:param weights: 各尺度的权重,默认等权重
:param normalize: 是否进行结果归一化
:return: 增强后的图像
"""
# 如果没有提供权重,则使用等权重
if weights is None:
weights = [1.0 / len(sigma_list)] * len(sigma_list)
elif len(weights) != len(sigma_list):
raise ValueError("权重列表长度必须与sigma_list相同")
# 转换为浮点型并加1避免log(0)
img = img.astype(np.float32) / 255.0 + 1e-6
# 初始化MSR结果
msr = np.zeros_like(img)
# 对每个尺度进行处理
for sigma, weight in zip(sigma_list, weights):
# 分别处理每个通道
channels = []
for ch in range(3):
img_ch = img[:, :, ch]
# 高斯模糊估计光照分量
gaussian = cv2.GaussianBlur(
src=img_ch,
ksize=(0, 0),
sigmaX=sigma,
sigmaY=sigma
)
# 对数域减法分离反射分量
retinex = np.log(img_ch) - np.log(gaussian)
channels.append(retinex)
# 加权累加到MSR结果
msr += weight * np.stack(channels, axis=2)
# 可选归一化 (增强视觉效果)
if normalize:
# 将结果缩放到0~255
msr = (msr - np.min(msr)) / (np.max(msr) - np.min(msr))
msr = (msr * 255).astype(np.uint8)
return msr
# 示例使用
if __name__ == "__main__":
# 读取图像
image = cv2.imread('img_1.png') # 替换为你的图像路径
# 应用MSR (三个尺度)
msr_result = multi_scale_retinex(
image,
sigma_list=[15, 80, 250], # 小、中、大三个尺度
weights=[0.4, 0.3, 0.3], # 权重分配
normalize=True
)
# 保存结果
cv2.imwrite('msr_enhanced.png', msr_result)
# 与单尺度结果对比
ssr_small = multi_scale_retinex(image, sigma_list=[15])
ssr_medium = multi_scale_retinex(image, sigma_list=[80])
ssr_large = multi_scale_retinex(image, sigma_list=[250])
# 对比显示
plt.figure(figsize=(18, 10))
plt.subplot(231)
plt.title("Original Image")
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.subplot(232)
plt.title("SSR (Small Scale, σ=15)")
plt.imshow(cv2.cvtColor(ssr_small, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.subplot(233)
plt.title("SSR (Medium Scale, σ=80)")
plt.imshow(cv2.cvtColor(ssr_medium, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.subplot(234)
plt.title("SSR (Large Scale, σ=250)")
plt.imshow(cv2.cvtColor(ssr_large, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.subplot(235)
plt.title("MSR (Multi-Scale)")
plt.imshow(cv2.cvtColor(msr_result, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.tight_layout()
plt.savefig('msr_comparison.jpg', dpi=300, bbox_inches='tight')
plt.show()
结果图像
输入图像:
增强图像:
3. 多尺度 Retinex 颜色恢复(MSRCR, Multi - Scale Retinex with Color Restoration)
核心思想:在 MSR 基础上,增加**颜色恢复(Color Restoration)**步骤,解决色偏问题。
步骤:
-
多尺度 Retinex(MSR) :
同 MSR 步骤,得到反射分量的对数 ( \log® )。
-
颜色恢复(Color Restoration) :
用原始图像的颜色统计信息,补偿反射分量的色偏。公式(以 RGB 通道为例):
CRc=β⋅[log(α⋅Ic)−log(∑c=R,G,BIc)] CR_c = \beta \cdot \left[ \log(\alpha \cdot I_c) - \log\left( \sum_{c=R,G,B} I_c \right) \right] CRc=β⋅ log(α⋅Ic)−log c=R,G,B∑Ic- ( CR_c ):通道 ( c ) 的颜色恢复因子
- ( \alpha, \beta ):调整参数(控制颜色恢复强度,需经验调参)
- 作用:让颜色更贴近原始图像的色彩分布,避免 MSR 导致的色偏。
-
融合反射与颜色恢复 :
最终增强公式:
MSRCR=G⋅(R⋅CR+b) MSRCR = G \cdot \left( R \cdot CR + b \right) MSRCR=G⋅(R⋅CR+b)- ( G ):增益系数(调整整体亮度)
- ( b ):偏移量(微调亮度基准)
-
颜色平衡(可选) :
对每个通道做直方图截断(如
simplestColorBalance
),限制极端亮度值,优化颜色分布。
特点:
- 优点:在 MSR 基础上解决色偏,增强后颜色更自然;适合低光、雾天等场景的图像增强。
- 缺点:参数多(( \sigma ) 组、( \alpha, \beta, G, b ) 等),需经验调参;计算复杂度高于 SSR/MSR。
代码实现
python
import numpy as np
import cv2
import matplotlib.pyplot as plt
# 单尺度 Retinex 计算
def singleScaleRetinex(img, sigma):
temp = cv2.GaussianBlur(img, (0, 0), sigma)
gaussian = np.where(temp == 0, 0.01, temp)
retinex = np.log10(img + 0.01) - np.log10(gaussian)
return retinex
# 多尺度 Retinex 计算
def multiScaleRetinex(img, sigma_list):
retinex = np.zeros_like(img, dtype=np.float64)
for sigma in sigma_list:
retinex += singleScaleRetinex(img, sigma)
retinex = retinex / len(sigma_list)
return retinex
# 颜色恢复
def colorRestoration(img, alpha, beta):
img_sum = np.sum(img, axis=2, keepdims=True)
color_restoration = beta * (np.log10(alpha * img) - np.log10(img_sum))
return color_restoration
# 简单颜色平衡
def simplestColorBalance(img, low_clip, high_clip):
total = img.shape[0] * img.shape[1]
for i in range(img.shape[2]):
current = img[:, :, i]
unique, counts = np.unique(current, return_counts=True)
low_val = 0
high_val = 0
cumulative_count = 0
for u, c in zip(unique, counts):
if float(cumulative_count) / total < low_clip:
low_val = u
cumulative_count += c
elif float(cumulative_count) / total < high_clip:
high_val = u
cumulative_count += c
else:
if high_val == 0:
high_val = u
break
current = np.maximum(np.minimum(current, high_val), low_val)
img[:, :, i] = current
return img
# MSRCR 算法实现
def MSRCR(img, sigma_list, G, b, alpha, beta, low_clip, high_clip):
img = np.float64(img) + 1.0
img_retinex = multiScaleRetinex(img, sigma_list)
img_color = colorRestoration(img, alpha, beta)
img_msrcr = G * (img_retinex * img_color + b)
for i in range(img_msrcr.shape[2]):
img_msrcr[:, :, i] = (img_msrcr[:, :, i] - np.min(img_msrcr[:, :, i])) / \
(np.max(img_msrcr[:, :, i]) - np.min(img_msrcr[:, :, i])) * 255
img_msrcr = np.uint8(np.minimum(np.maximum(img_msrcr, 0), 255))
img_msrcr = simplestColorBalance(img_msrcr, low_clip, high_clip)
return img_msrcr
if __name__ == "__main__":
# 读取图像
image_path = r'E:\lgl\DeepLearning\retinex\img_1.png' # 替换为你的图像路径
img = cv2.imread(image_path)
if img is None:
print("无法读取图像,请检查路径是否正确。")
else:
# 设置参数
sigma_list = [15, 80, 250] # 多尺度的 sigma 值
G = 5 # 增益系数
b = 20 # 偏移量
alpha = 125 # 颜色恢复参数 alpha
beta = 46 # 颜色恢复参数 beta
low_clip = 0.01 # 颜色平衡低阈值
high_clip = 0.99 # 颜色平衡高阈值
# 应用 MSRCR 算法
result = MSRCR(img, sigma_list, G, b, alpha, beta, low_clip, high_clip)
cv2.imwrite('enhanced_image.png', result)
# 显示原始图像和处理后的图像(需要导入 matplotlib 库)
plt.subplot(121)
plt.title("Original Image")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.subplot(122)
plt.title("MSRCR Enhanced")
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.tight_layout()
plt.savefig('msrcr_result.jpg', dpi=300)
plt.show()
结果图像
输入图像:
增强图像:
三类算法对比
算法 | 核心优势 | 典型应用场景 | 不足 |
---|---|---|---|
SSR | 计算简单,局部细节增强效果明显 | 小范围细节优化(如医学图像) | 尺度单一,适应性差 |
MSR | 多尺度平衡,兼顾全局与局部增强 | 通用图像增强(如监控、遥感) | 易色偏,无颜色恢复机制 |
MSRCR | 多尺度 + 颜色恢复,自然还原色彩 | 低光、雾天图像(如夜景、航拍) | 参数多,计算复杂度高 |
总结
Retinex 系列算法的本质是分离光照和反射,通过增强反射分量(细节)提升图像质量:
- SSR 是基础,适合简单场景;
- MSR 用多尺度弥补 SSR 的局限性;
- MSRCR 进一步加入颜色恢复,解决色偏问题,是更实用的工程方案(如低光图像增强、去雾等任务)。
实际使用中,MSRCR 因颜色自然更常用,但需注意参数调优(尤其是 ( \sigma ) 组和颜色恢复参数);若追求极致效率,SSR 或 MSR 也可根据场景适配。