水下图像太蓝看不清?手把手教你用Python+OpenCV复现COLOR TRANSFER去雾算法(附代码)

张开发
2026/6/16 17:24:48 15 分钟阅读
水下图像太蓝看不清?手把手教你用Python+OpenCV复现COLOR TRANSFER去雾算法(附代码)
水下图像去雾实战用Python实现COLOR TRANSFER算法每次潜水拍摄回来的照片总是蓝得发慌别急着删这可能只是光线在水下的恶作剧。水下摄影爱好者常遇到这样的困扰明明肉眼看到的珊瑚色彩斑斓拍出来却像蒙了一层蓝色滤镜。今天我们就用PythonOpenCV从零实现一篇经典论文中的COLOR TRANSFER技术让这些蓝精灵照片重获新生。1. 环境准备与基础知识1.1 工具链搭建首先确保你的Python环境已经就绪。推荐使用Anaconda创建独立环境conda create -n underwater python3.8 conda activate underwater pip install opencv-python numpy matplotlib scikit-image关键库版本要求OpenCV ≥ 4.5包含完整的图像处理工具链NumPy ≥ 1.20高效的矩阵运算支持scikit-image提供颜色空间转换工具提示如果处理4K分辨率图像建议安装opencv-contrib-python以获取更快的DNN模块支持1.2 水下成像原理速成水对光线的吸收不是均匀的不同波长的光衰减程度不同颜色通道衰减系数(η)穿透深度(米)红色0.3-0.53-5绿色0.1-0.28-10蓝色0.05-0.115-20这就是为什么水下照片普遍偏蓝的原因。COLOR TRANSFER算法的核心思想是从一张在清澈水域拍摄的参考图中借用颜色特征来校正雾化图像的颜色偏差。2. 算法实现步骤拆解2.1 图像分层处理直接应用颜色迁移会导致细节丢失我们采用引导滤波将图像分解def guided_filter(I, p, radius15, eps1e-3): 引导滤波实现图像分层 mean_I cv2.boxFilter(I, cv2.CV_64F, (radius, radius)) mean_p cv2.boxFilter(p, cv2.CV_64F, (radius, radius)) mean_Ip cv2.boxFilter(I * p, cv2.CV_64F, (radius, radius)) cov_Ip mean_Ip - mean_I * mean_p mean_II cv2.boxFilter(I * I, cv2.CV_64F, (radius, radius)) var_I mean_II - mean_I * mean_I a cov_Ip / (var_I eps) b mean_p - a * mean_I mean_a cv2.boxFilter(a, cv2.CV_64F, (radius, radius)) mean_b cv2.boxFilter(b, cv2.CV_64F, (radius, radius)) return mean_a * I mean_b处理流程对输入图像进行引导滤波得到基础层原始图像减去基础层得到细节层仅对基础层进行颜色迁移最后合并处理后的基础层与原始细节层2.2 颜色空间转换RGB空间不适合直接进行颜色迁移我们需要转换到lαβ空间def rgb_to_lab(img_rgb): RGB到lαβ颜色空间转换 # 先转换到XYZ空间 xyz cv2.cvtColor(img_rgb, cv2.COLOR_BGR2XYZ) # 转换到LMS空间 lms np.dot(xyz, np.array([[0.3897, 0.6890, -0.0787], [-0.2298, 1.1834, 0.0464], [0.0, 0.0, 1.0]])) # 对数变换 lms np.log10(np.maximum(lms, 1e-6)) # 转换到lαβ空间 lab np.dot(lms, np.array([[1/np.sqrt(3), 0, 0], [0, 1/np.sqrt(6), 0], [0, 0, 1/np.sqrt(2)]])) lab np.dot(lab, np.array([[1, 1, 1], [1, 1, -2], [1, -1, 0]])) return lab关键参数说明l通道亮度信息α通道黄蓝对立色信息β通道红绿对立色信息3. 核心算法实现3.1 颜色迁移主函数def color_transfer(src, ref): 核心颜色迁移函数 # 转换到lαβ空间 src_lab rgb_to_lab(src) ref_lab rgb_to_lab(ref) # 计算均值和标准差 src_mean, src_std np.mean(src_lab, axis(0,1)), np.std(src_lab, axis(0,1)) ref_mean, ref_std np.mean(ref_lab, axis(0,1)), np.std(ref_lab, axis(0,1)) # 颜色迁移 lab src_lab - src_mean lab lab * (ref_std / src_std) lab lab ref_mean # 逆转换回RGB return lab_to_rgb(lab)3.2 完整处理流程def underwater_dehazing(input_img, ref_img): 完整的水下去雾流程 # 图像分层 base_layer guided_filter(cv2.cvtColor(input_img, cv2.COLOR_BGR2GRAY), input_img.astype(np.float32)/255) detail_layer input_img.astype(np.float32)/255 - base_layer # 基础层颜色迁移 base_layer_corrected color_transfer((base_layer*255).astype(np.uint8), ref_img) # 合并结果 result np.clip(base_layer_corrected detail_layer, 0, 1) return (result * 255).astype(np.uint8)4. 实战调优技巧4.1 参考图选择原则不是随便找张清晰图片就能当参考图理想参考图应满足拍摄环境相似相同水域、相近深度拍摄的图片最佳色彩特征明显包含红、黄等易衰减颜色的物体光照条件良好自然光充足或人工补光均匀无强烈反光避免水面反射光造成的过曝区域4.2 参数调优指南参数推荐范围影响效果调整策略引导滤波半径15-30基础层平滑程度图像噪声大时增大引导滤波ε1e-3~1e-2边缘保持能力需要锐利边缘时减小颜色迁移强度0.5-1.2色彩校正幅度根据水质浑浊度调整4.3 效果增强技巧多参考图融合对同一场景使用多张参考图的结果取平均局部颜色迁移对不同深度区域使用不同的参考图后处理锐化对细节层适当增强后再合并# 细节层增强示例 enhanced_detail detail_layer * 1.5 # 增强系数 result np.clip(base_layer_corrected enhanced_detail, 0, 1)5. 进阶应用与效果评估5.1 与深度估计结合通过颜色校正后的图像可以更准确地进行深度估计def estimate_depth(dehazed_img): 基于暗通道的深度估计 dark_channel np.min(dehazed_img, axis2) depth_map -np.log(dark_channel / 255.0 1e-6) return cv2.normalize(depth_map, None, 0, 255, cv2.NORM_MINMAX)5.2 效果评估指标实现这些评估函数来量化改进效果def ucique_metric(img): 水下图像质量评估 # 实现细节参考相关论文 pass def pcqi_metric(img1, img2): 对比度质量指数 # 实现细节参考相关论文 pass在实际项目中我发现当参考图与被处理图像的光照角度相似时颜色迁移效果最自然。有一次处理一组沉船照片尝试了5种不同参考图后最终选择了一张同位置但更浅水域拍摄的照片作为参考得到了最满意的色彩还原效果。

更多文章