You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何实现彩色图像光照均匀化?含已尝试代码及效果需求

解决图像光照均匀化问题的改进方案

看起来你当前的代码主要依赖CLAHE做局部对比度增强,但后续的锐化、二值化步骤其实偏离了「全局光照一致」的核心目标,而且CLAHE本身是局部增强,对于全局明暗不均的场景(比如一半亮一半暗的图像)效果有限。我来给你几个针对性的改进思路和代码示例:

问题分析

你的现有流程存在几个和目标不符的点:

  • 转LAB空间用CLAHE增强L通道:CLAHE擅长提升局部暗部细节,但不会平衡全局光照,甚至可能让局部过曝或噪点加重
  • 后续的锐化、阈值、降噪:这些是针对二值化的操作,会丢失原始图像的色彩和亮度层次,完全不符合「全局光照一致」的输出要求

改进方案1:全局光照估计与补偿

这个方法的核心是先估算图像的光照分量,再用原图除以光照分量来抵消光照不均,适合处理全局明暗差异大的场景:

import cv2
import numpy as np

def normalize_illumination(img):
    # 转灰度图用于估算光照
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 大尺寸高斯模糊获取全局光照分布(核大小可根据图像尺寸调整)
    illumination = cv2.GaussianBlur(gray, (151, 151), 0)
    # 归一化光照图到0-1范围
    illumination = illumination.astype(np.float32) / 255.0
    # 原图转浮点型,对每个通道做光照补偿
    img_float = img.astype(np.float32) / 255.0
    normalized = np.zeros_like(img_float)
    for i in range(3):
        normalized[..., i] = img_float[..., i] / illumination
    # 把结果限制在0-255范围内并转成uint8格式
    normalized = np.clip(normalized * 255, 0, 255).astype(np.uint8)
    return normalized

# 测试代码
img = cv2.imread('new_sample/sample6.jpg', 1)
original = img.copy()
normalized_img = normalize_illumination(img)

# 对比显示结果
stack_horizontal = np.concatenate((original, normalized_img), axis=1)
cv2.imshow('Original vs Illumination Normalized', cv2.resize(stack_horizontal, (800, 600)))
cv2.imwrite("illumination_normalized.jpg", normalized_img)
cv2.waitKey()
cv2.destroyAllWindows()

改进方案2:CLAHE结合全局亮度校准

如果还是想用CLAHE,可以先调整全局亮度,再做局部增强,避免局部过度增强的问题:

import cv2
import numpy as np

img = cv2.imread('new_sample/sample6.jpg', 1)
original = img.copy()

lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)

# 先把全局L通道亮度校准到均值127(中间灰),平衡整体明暗
l_mean = np.mean(l)
l_global = cv2.convertScaleAbs(l, alpha=127/l_mean, beta=0)

# 降低CLAHE的clipLimit,避免局部过度增强,同时增大tileGridSize覆盖更大区域
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(16, 16))
l_clahe = clahe.apply(l_global)

limg = cv2.merge((l_clahe, a, b))
final = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)

# 对比显示结果
stack_horizontal = np.concatenate((original, final), axis=1)
cv2.imshow('Original vs Improved CLAHE', cv2.resize(stack_horizontal, (800, 600)))
cv2.imwrite("clahe_improved.jpg", final)
cv2.waitKey()
cv2.destroyAllWindows()

改进方案3:Retinex算法(专业光照平衡)

Retinex算法专门针对光照不均场景,能同时保留细节和平衡全局光照,这里是简化版的多尺度实现:

import cv2
import numpy as np

def single_scale_retinex(img, sigma):
    img_float = img.astype(np.float32) + 1e-8  # 避免除0错误
    log_img = np.log10(img_float)
    blur = cv2.GaussianBlur(img_float, (0,0), sigma)
    log_blur = np.log10(blur)
    retinex = log_img - log_blur
    # 归一化到0-255范围
    retinex = (retinex - np.min(retinex)) / (np.max(retinex) - np.min(retinex)) * 255
    return retinex.astype(np.uint8)

def multi_scale_retinex(img, sigmas=[15, 80, 250]):
    retinex = np.zeros_like(img, dtype=np.float32)
    # 多尺度融合,兼顾局部和全局光照
    for sigma in sigmas:
        retinex += single_scale_retinex(img, sigma)
    retinex /= len(sigmas)
    return retinex.astype(np.uint8)

# 测试代码
img = cv2.imread('new_sample/sample6.jpg', 1)
original = img.copy()
msr_img = multi_scale_retinex(img)

# 对比显示结果
stack_horizontal = np.concatenate((original, msr_img), axis=1)
cv2.imshow('Original vs MSR Normalized', cv2.resize(stack_horizontal, (800, 600)))
cv2.imwrite("msr_normalized.jpg", msr_img)
cv2.waitKey()
cv2.destroyAllWindows()

你可以根据自己的图像场景选择合适的方案:如果是全局明暗差异大,优先用方案1;如果是局部暗部细节不足但全局光照还行,用方案2;如果追求更专业的光照平衡效果,方案3的Retinex会更合适。

内容的提问来源于stack exchange,提问作者Naman Gupta

火山引擎 最新活动