2024年亚太杯APMCM数学建模大赛A题复杂场景下水下图像增强研究解题全过程文档及程序

2024年亚太杯APMCM数学建模大赛

A题 复杂场景下水下图像增强研究

原题再现

在海洋探测中,清晰、高质量的水下图像对于深海地形测量和海底资源勘探至关重要。然而,在复杂水下环境中,光线在水中传播时会发生吸收和散射现象,导致图像质量下降,出现模糊、对比度低、颜色失真等问题,这些现象统称为水下图像退化。
  水下图像退化的主要成因包括:水中的光传播损耗、前向散射与后向散射效应,以及悬浮颗粒物对光线的散射作用。这些因素共同导致水下图像在传输过程中丢失细节与清晰度,影响视觉识别与分析。

  水下成像过程示意图如图 2 所示。根据 Jaffe-McGlamery 水下成像模型,相机所采集到的水下退化图像可表示为三个分量的线性组合:直达分量、前向散射分量、后向散射分量。其中:
前向散射分量指目标表面反射或辐射的光线经水中悬浮颗粒散射后进入成像系统,会导致图像模糊。
  后向散射分量指自然光入射水体后经悬浮颗粒散射进入成像系统,会导致图像对比度降低。
  在一般情况下,由于目标与相机距离较近,可采用简化成像模型:

  其中:
  I (x) 表示退化后的水下图像
  J (x) 表示清晰原始图像
  B 为水下环境光
  t (x) 为水下场景光透射率函数
  光透射率随环境条件变化,同时水下环境光也会随水深、水体浊度等因素改变,这些都会加剧图像退化。

  在对水下图像进行增强等处理前,需要对图像进行统计分析,如图 3 所示。图像分析通常结合数学模型与图像处理技术,挖掘底层特征与高层结构,从而提取有效信息。例如,利用直方图可统计分析图像各通道颜色分布,使用边缘算子可获取图像中目标轮廓的清晰程度信息。这些信息有助于将图像划分为不同类别,并提出针对性的图像增强方案。

  水下图像增强技术,是运用信号处理、图像处理与机器学习理论,提升水下环境采集图像质量的技术。其目标是缓解因水中光吸收、散射导致的图像模糊、颜色失真、对比度下降等问题,提高水下图像的可视性与清晰度。
  水下图像增强与复原方法可分为传统方法与深度学习方法两大类。传统方法又可分为非物理模型方法与基于物理模型方法:
  非物理模型方法:直接调整图像像素值提升视觉效果,包括通用图像增强方法与专门设计的算法。
  基于物理模型方法:通过建模与参数估计,逆向求解水下图像的退化过程。这类方法可基于假设或先验知识进行反演,也可利用水下成像的光学特性优化复原结果。
但由于水下场景复杂,现有多数方法难以适配所有场景。因此,面向复杂场景设计专用的水下场景增强算法,对后续水下视觉任务具有重要意义。
  问题 1
  请使用与文中类似的图像统计分析技术,对附件 1 提供的水下图像进行多角度分析。将附件 1 图像分为色偏、低光照、模糊三类,并将文件名填入附件 "Answer.xls" 的对应位置,同时说明分类依据。
  问题 2
  基于问题 1 提出的退化类型,利用题目给出的水下成像模型,结合附件图像构建水下场景图像退化模型。分析不同场景下水下图像的退化原因(包括但不限于色偏、低光照等),并分析这些退化模型的异同点(可从颜色、光照、清晰度等角度分类)。
  问题 3
  基于问题 2 建立的水下场景图像退化模型,针对单一退化场景(色偏 / 模糊 / 低光照)提出一种水下图像增强方法,并使用附件提供的图像数据验证所提方法。在论文中展示附件 2 测试图像的增强结果及对应评价指标,计算并给出输出图像的 PSNR、UCIQE、UIQM 等指标,并填入 "Answer.xls" 中的附件 1 结果表。
  问题 4
  现有水下图像增强模型在不同场景下的建模适配性存在差异。结合上述问题与附件图像,面向复杂场景提出一种通用水下图像增强模型(可采用非物理模型,参考文献 [2]-[5])。该模型应能对多种复杂场景下的水下图像退化问题进行增强。在论文中展示附件 2 测试图像的增强结果及对应评价指标,计算并输出图像的 PSNR、UCIQE、UIQM,并填入 "Answer.xls" 中的附件 2 结果表。
  问题 5
  对比面向特定场景的多种增强技术与面向复杂场景的单一增强技术,为实际应用中的水下视觉增强提出可行性建议。

整体求解过程概述(摘要)

水下成像具有成本高昂、容错率极低的特点,受水体中光线吸收、散射以及悬浮颗粒干扰等因素影响,水下图像极易出现色偏、低光照、模糊等退化现象。如何对退化水下图像进行有效修复与增强,已成为海洋科研、水下探测、海洋工程等领域的关键技术难题。为此,本文综合运用水下光学成像物理定理与机器学习方法,对水下退化图像开展系统性的多维度分类、退化机理建模、针对性增强与泛化复原研究,旨在实现复杂水下环境的图像质量提升。
  针对问题一,本文首先通过视觉特征分析,确定各类退化现象在直观表现上的优先级次序:低光照最为显著,色偏次之,模糊相对最弱,并依据该优先级建立分级判别机制。在此基础上,构建灰度直方图亮度分析模型以判断图像欠曝光程度;建立RGB 三通道直方图模型,结合Jensen‑Shannon 散度(JSD) 实现色偏程度的量化评价;采用拉普拉斯算子计算响应方差,实现图像模糊程度的自动判别。最终完成对附件 1 中全部图像的分类统计,共识别出模糊图像 33 张、色偏图像 215 张、低光照图像 22 张、正常清晰图像 130 张。
  针对问题二,基于经典 Jaffe‑McGlamery 水下光学成像模型,本文提出一种简化且经过修正的水下成像模型,使其更贴近实际近距离拍摄场景。通过对成像公式进行分解与简化,使其适配单一主导退化类型,进而分别构建色偏退化模型、低光照退化模型、清晰度退化模型。为提升数据可靠性,本文采用一种创新的统计预处理方法 ------噪声对抗预处理(NAP),对附件 1 数据集进行降噪与规整处理;随后结合最小二乘法与指数平滑法拟合求解直达衰减系数(\beta_{c}{D})与后向散射系数(\beta_{c}^{B})的近似值,并分析参数合理性、剔除异常数据,最终对比不同退化模型的物理机理、表现特征与异同规律。
  针对问题三,面向三类单一退化场景分别提出定制化增强策略。对于模糊图像,采用先去噪、再锐化、最后增强对比度的三步融合增强策略,有效恢复边缘与细节;对于色偏图像,构建前后向随机森林模型(FbRF),利用前后向理论扩展数据集并学习色偏校正规律;对于低光照图像,采用灰度自适应调整与 CLAHE 增强方法。随后通过PSNR、UCIQE、UIQM三项无参考与全参考指标对增强效果进行量化验证,结果表明所提方法具有显著提升作用。同时,本文深入分析了 FbRF 色偏校正模型对 UCIQE 指标不敏感的内在原因。
  针对问题四与问题五,本文系统分析现有水下图像增强方法在复杂混合退化场景中的缺陷,指出模型泛化性不足、单一增强策略难以适用多类型退化等问题。据此提出一种基于多尺度 N 折融合的多重复合增强模型,将物理模型的可解释性与机器学习的泛化能力相结合,实现对复杂场景的统一增强。在详细阐述模型流程后,将其应用于附件 2 图像增强处理,实验结果充分证明该模型在同时处理色偏、低光照、模糊等问题时的综合优势。为更全面评价图像质量,引入SIFT 尺度不变特征变换提取特征点数量作为细节丰富度的辅助评价依据。最后结合实际工程应用需求,分别面向单一典型退化场景与复杂混合退化场景,提出水下视觉增强的可行性建议与工程化思路。
  最后,本文对问题二所建立的水下退化物理模型进行参数灵敏度分析,验证模型稳定性;对多重复合增强模型进行鲁棒性测试,检验其对抗噪声与异常数据的能力。同时全面总结模型的优势与不足,分析其在实际应用中的局限性,并对未来水下图像增强研究方向进行展望。

模型假设:

为合理简化问题、提升模型可实现性,并使建模过程更贴近真实水下环境,本文结合水下光学传播规律与工程实际,提出以下基本假设,并对每条假设给出合理性说明。
  (1)退化特征相互独立性假设
水下图像的各类典型退化现象(如色偏、低光照、模糊)在一定程度上可视为相互独立的特征。这意味着在特定场景下,可针对单一退化类型分别设计检测、判别与增强算法,而无需过度考虑各类退化之间的复杂耦合与交互影响。该假设能够显著降低模型设计难度,使单场景增强策略更具针对性与可解释性,同时保证在主导退化明确的条件下仍具有较高精度。
  (2)物理模型泛化性假设
本文所采用的水下图像退化物理模型对浅海、深海、浑浊水体等多数典型水下环境均具有适用性。尽管不同水深、浊度、光照条件下图像退化强度存在差异,但控制退化的核心物理机理(如水体对光的选择性吸收、前向 / 后向散射、悬浮颗粒衰减等)保持一致,仅需通过调整模型中的光学参数即可实现对不同环境的适配。该假设保证了模型的通用性与跨场景迁移能力。
  (3)前向散射可忽略假设
在强散射、高浊度极端水环境中,完全忽略前向散射分量的假设不再严格成立。但在常规水下探测任务中,此类极端环境出现概率较低;且在相机与拍摄目标距离较近的通用条件下,前向散射对成像结果的影响远小于后向散射与直达光衰减。因此在 Jaffe-McGlamery 成像模型中,合理忽略前向散射分量,能够在保证精度的前提下大幅简化模型求解与参数估计过程。
  (4)光照平滑场景先验假设
水下复杂光照易导致非均匀色偏、局部高亮、区域过度增强与细节丢失等问题。由于复杂光场具有强随机性、非均匀性与难以建模的混沌特性,难以通过统一的物理与数学模型精确描述。因此本文主要考虑无遮挡自然光在水体中的均匀衰减过程,暂不考虑人工补光、局部强光源、阴影遮挡、反射光斑等复杂光照情况。该假设使模型更聚焦于核心退化机理,保证增强方法稳定可靠。

问题分析:

问题一要求对水下图像进行多维度统计分析,并按照色偏、低光照、模糊三类进行自动分类。首先需要明确三类退化在视觉与像素分布上的典型特征:低光照表现为整体亮度不足、灰度直方图偏左;色偏表现为 RGB 三通道分布不均衡;模糊表现为边缘信息缺失、细节平滑。
  为了实现客观分类,需分别构建亮度判别模型、色偏量化模型与清晰度判别模型,避免人工主观判断带来的误差。因此,可采用灰度累积分布函数判断欠曝光;利用RGB 直方图与 JS 散度衡量通道差异以识别色偏;通过拉普拉斯方差反映图像边缘强度,实现模糊程度自动判别。最终依据退化显著性优先级(低光照→色偏→模糊)完成全图像集分类。
  问题二要求基于 Jaffe-McGlamery 水下成像模型,构建色偏、低光照、模糊对应的退化模型,并比较模型异同。水下图像退化本质是水体对光的吸收、散射、透射衰减共同作用的结果,不同退化类型对应模型中不同物理项的主导作用。
  色偏主要由 RGB 三通道衰减系数不一致导致;低光照由环境光衰减与后向散射共同决定;模糊由悬浮颗粒前向散射与运动模糊造成。因此需要对经典成像模型进行简化修正,并分别推导三类退化的数学表达,再通过数据拟合光学参数,分析不同退化机制的物理差异与共性规律。同时,原始数据存在噪声与异常点,需通过 ** 噪声对抗预处理(NAP)** 提升模型稳定性。
  问题三要求针对单一退化类型设计专用增强算法,并使用 PSNR、UCIQE、UIQM 进行验证。由于三类退化成因不同,统一增强方法难以达到最优效果,因此应采用分治策略:模糊图像需先降噪再锐化,最后提升对比度;色偏图像需要学习正常与色偏图像间的映射关系,实现通道补偿;低光照图像需在保留细节前提下提升亮度与局部对比度。通过针对性处理可最大程度还原图像信息,再利用多指标综合评价增强效果,确保算法可靠有效。
  问题四要求构建适用于复杂混合退化场景的通用增强模型。实际水下图像往往同时存在色偏、模糊、低光照,单一算法无法全面修复。传统物理模型依赖参数估计,泛化性弱;机器学习模型依赖数据集,鲁棒性不足。因此需要构建多重复合模型,融合物理先验与机器学习优势,通过多尺度 N 折融合与 Alpha 混合将去雾、锐化、色偏校正、亮度增强多路结果加权融合,使模型能同时处理多种退化。同时引入 SIFT 特征点数量辅助评价细节恢复效果,提升评价全面性。
  问题五要求对比专用增强算法与通用复合模型的优劣,并给出工程建议。专用算法在单一退化上效果更精准、计算更快,但泛化性差;通用模型可处理复杂场景,但结构更复杂、计算量更大。实际工程中需根据环境稳定程度、硬件算力、实时性要求选择策略。因此应从算法融合、多模态感知、轻量化部署、数据集建设等方面提出可行性建议,使水下视觉增强在真实场景中更实用、鲁棒、可靠。

模型的建立与求解整体论文缩略图

全部论文及程序请见下方" 只会建模 QQ名片" 点击QQ名片即可

部分程序代码:

python 复制代码
"""
============================================================
水下图像增强系统 - 完整实现
============================================================
问题一:水下图像退化分类(低光照、色偏、模糊、正常)
问题二:Jaffe-McGlamery水下成像模型建立与参数估计
问题三:单一退化类型定制化增强策略
问题四/五:多重复合增强模型与泛化复原
============================================================
"""

import numpy as np
import cv2
from scipy.spatial.distance import jensenshannon
from sklearn.ensemble import RandomForestRegressor
from collections import Counter
import warnings
warnings.filterwarnings('ignore')

# ============================================================
# 第一部分:问题一 - 水下图像退化分类系统
# ============================================================

class UnderwaterImageClassifier:
    """
    水下图像退化分类器
    优先级:低光照 > 色偏 > 模糊 > 正常
    """

    def __init__(self, low_light_threshold=80, color_bias_threshold=0.15, 
                 blur_threshold=100):
        self.low_light_threshold = low_light_threshold
        self.color_bias_threshold = color_bias_threshold
        self.blur_threshold = blur_threshold

    def analyze_brightness(self, image):
        """灰度直方图亮度分析模型"""
        if len(image.shape) == 3:
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        else:
            gray = image

        hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
        hist = hist.flatten() / hist.sum()
        avg_brightness = np.mean(gray)
        is_low_light = avg_brightness < self.low_light_threshold

        return {
            'avg_brightness': avg_brightness,


        jsd_rg = jensenshannon(hist_r, hist_g)
        jsd_rb = jensenshannon(hist_r, hist_b)
        jsd_gb = jensenshannon(hist_g, hist_b)

        jsd_score = np.nanmean([jsd_rg, jsd_rb, jsd_gb])

        channel_means = {'R': np.mean(r), 'G': np.mean(g), 'B': np.mean(b)}
        dominant_channel = max(channel_means, key=channel_means.get)

        is_color_biased = jsd_score > self.color_bias_threshold

        return {
            'jsd_score': jsd_score,
            'dominant_channel': dominant_channel,
            'channel_means': channel_means,
            'is_color_biased': is_color_biased
        }

    def analyze_blur(self, image):
        """拉普拉斯算子响应方差模糊判别"""
        if len(image.shape) == 3:
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        else:
            gray = image

        laplacian = cv2.Laplacian(gray, cv2.CV_64F)
        laplacian_var = laplacian.var()
        is_blurry = laplacian_var < self.blur_threshold

        return {
            'laplacian_var': laplacian_var,
            'is_blurry': is_blurry

            'brightness': brightness_result,
            'color': color_result,
            'blur': blur_result
        }

        return category, scores

    def batch_classify(self, image_dir):
        """批量分类目录下所有图像"""
        import os
        results = {}
        categories = []
        valid_ext = ('.jpg', '.jpeg', '.png', '.bmp', '.tiff')

        for filename in sorted(os.listdir(image_dir)):
            if filename.lower().endswith(valid_ext):
                filepath = os.path.join(image_dir, filename)
                try:
                    img = cv2.imread(filepath)
                    if img is not None:
                        category, scores = self.classify(img)
                        results[filename] = {'category': category, 'scores': scores}
                        categories.append(category)
                except Exception as e:
                    print(f"处理 {filename} 时出错: {e}")

        statistics = dict(Counter(categories))
        return results, statistics


# ============================================================
# 第二部分:问题二 - Jaffe-McGlamery水下成像模型
# ============================================================

class UnderwaterImagingModel:
    """
    简化修正的Jaffe-McGlamery水下光学成像模型
    经典模型: I_c(x) = J_c(x)*e^(-beta_c*D) + B_c*(1-e^(-beta_c^B*D))
    """

    def __init__(self):
        self.beta_D = {}
        self.beta_B = {}
        self.background_light = {}

    def simplified_model(self, J, beta_D, beta_B, B, D=1.0):
        """简化的水下成像模型"""
        direct = J * np.exp(-beta_D)
        backscatter = B * (1 - np.exp(-beta_B))
        return direct + backscatter

    def noise_adversarial_preprocessing(self, image):
        """噪声对抗预处理 (NAP)"""
        gaussian = cv2.GaussianBlur(image, (5, 5), 1.0)
        median = cv2.medianBlur(gaussian, 5)
        lab = cv2.cvtColor(median, cv2.COLOR_BGR2LAB)
        l, a, b = cv2.split(lab)
        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        l = clahe.apply(l)
        lab = cv2.merge([l, a, b])
        result = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)
        return result

    def estimate_background_light(self, image):
        """估计背景光 B_c"""
        b, g, r = cv2.split(image)

        def estimate_channel(channel):
            flat = channel.flatten()
            top_percentile = int(len(flat) * 0.001)
            if top_percentile == 0:
                top_percentile = 1
            top_pixels = np.partition(flat, -top_percentile)[-top_percentile:]
            return np.mean(top_pixels)

        return {
            'B': estimate_channel(b),
            'G': estimate_channel(g),
            'R': estimate_channel(r)
        }

    def estimate_attenuation(self, degraded_img, clear_img, B, channel):
        """使用最小二乘法估计衰减系数"""
        if len(degraded_img.shape) == 3:
            b_d, g_d, r_d = cv2.split(degraded_img)
            b_c, g_c, r_c = cv2.split(clear_img)
            channel_map = {'B': (b_d, b_c), 'G': (g_d, g_c), 'R': (r_d, r_c)}
            I_deg, I_clear = channel_map.get(channel, (g_d, g_c))
        else:
            I_deg = degraded_img
            I_clear = clear_img

        I_deg = I_deg.astype(np.float64) / 255.0
        I_clear = I_clear.astype(np.float64) / 255.0
        B_val = B[channel] / 255.0

        I_clear = np.clip(I_clear, 1e-6, 1.0)
        ratio = I_deg / I_clear
        ratio = np.clip(ratio, 1e-6, 1.0)
        beta_D_est = -np.log(ratio)
        beta_D = np.median(beta_D_est)

        backscatter = I_deg - I_clear * np.exp(-beta_D)
        backscatter = np.clip(backscatter, 1e-6, None)
        if B_val > 1e-6:
            beta_B_est = -np.log(1 - backscatter / B_val)
            beta_B = np.median(np.clip(beta_B_est, 0, 5))
        else:
            beta_B = 0.1

        return beta_D, beta_B

    def fit_parameters(self, image_pairs, degradation_type):
        """拟合模型参数"""
        beta_D_list = {'B': [], 'G': [], 'R': []}
        beta_B_list = {'B': [], 'G': [], 'R': []}

        for deg_img, clear_img in image_pairs:
            deg_img = self.noise_adversarial_preprocessing(deg_img)
            B = self.estimate_background_light(deg_img)

            for channel in ['B', 'G', 'R']:
                try:
                    beta_D, beta_B = self.estimate_attenuation(
                        deg_img, clear_img, B, channel
                    )
                    if 0 < beta_D < 10 and 0 < beta_B < 10:
                        beta_D_list[channel].append(beta_D)
                        beta_B_list[channel].append(beta_B)
                except:
                    continue

        def exponential_smoothing(data, alpha=0.3):
            if len(data) == 0:
                return 0.5
            data = np.array(data)
            mean, std = np.mean(data), np.std(data)
            filtered = data[(data > mean - 3*std) & (data < mean + 3*std)]
            if len(filtered) == 0:
                filtered = data
            return np.median(filtered)

        for channel in ['B', 'G', 'R']:
            self.beta_D[channel] = exponential_smoothing(beta_D_list[channel])
            self.beta_B[channel] = exponential_smoothing(beta_B_list[channel])
            self.background_light[channel] = 0.8

        return {
            'beta_D': self.beta_D,
            'beta_B': self.beta_B,
            'B': self.background_light
        }

    def build_degradation_models(self):
        """构建三种退化模型"""
        return {
            'color_bias': {
                'description': '色偏退化模型 - 主要由波长相关衰减引起',
                'dominant_factor': 'beta_D',
                'characteristics': 'RGB通道衰减不均衡,呈现蓝/绿色偏'
            },
            'low_light': {
                'description': '低光照退化模型 - 光强整体衰减',
                'dominant_factor': 'beta_D + B',
                'characteristics': '整体亮度下降,对比度降低'
            },
            'blur': {
                'description': '清晰度退化模型 - 主要由后向散射引起',
                'dominant_factor': 'beta_B',
                'characteristics': '细节丢失,边缘模糊,对比度下降'
            }
        }


# ============================================================
# 第三部分:问题三 - 单一退化类型定制化增强策略
# ============================================================

class SingleDegradationEnhancer:
    """单一退化类型定制化增强器"""

    @staticmethod
    def enhance_blur(image):
        """模糊图像三步融合增强策略"""
        denoised = cv2.bilateralFilter(image, 9, 75, 75)
        gaussian = cv2.GaussianBlur(denoised, (0, 0), 3)
        sharpened = cv2.addWeighted(denoised, 1.5, gaussian, -0.5, 0)
        lab = cv2.cvtColor(sharpened, cv2.COLOR_BGR2LAB)
        l, a, b = cv2.split(lab)
        clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
        l = clahe.apply(l)
        lab = cv2.merge([l, a, b])
        enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)
        return enhanced

    @staticmethod
    def enhance_low_light(image):
        """低光照图像增强"""
        lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
        l, a, b = cv2.split(lab)
        l_float = l.astype(np.float32)
        mean_l = np.mean(l_float)
        gamma = np.log(128) / np.log(mean_l + 1e-6)
        gamma = np.clip(gamma, 0.5, 3.0)
        l_adjusted = np.power(l_float / 255.0, gamma) * 255.0
        l_adjusted = np.clip(l_adjusted, 0, 255).astype(np.uint8)
        clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(8, 8))
        l_enhanced = clahe.apply(l_adjusted)
        lab_enhanced = cv2.merge([l_enhanced, a, b])
        enhanced = cv2.cvtColor(lab_enhanced, cv2.COLOR_LAB2BGR)
        return enhanced

    class ForwardBackwardRF:
        """前后向随机森林模型 (FbRF) - 色偏校正"""

        def __init__(self, n_estimators=100):
            self.rf_models = {
                'B': RandomForestRegressor(n_estimators=n_estimators, random_state=42),
                'G': RandomForestRegressor(n_estimators=n_estimators, random_state=42),
                'R': RandomForestRegressor(n_estimators=n_estimators, random_state=42)
            }
            self.is_trained = False

        def extract_features(self, image):
            b, g, r = cv2.split(image)
            features = []
            for channel in [b, g, r]:
                features.extend([
                    np.mean(channel), np.std(channel),
                    np.percentile(channel, 25), np.percentile(channel, 50),
                    np.percentile(channel, 75), np.max(channel), np.min(channel)
                ])
            features.extend([
                np.mean(b) / (np.mean(g) + 1e-6),
                np.mean(r) / (np.mean(g) + 1e-6),
                np.mean(b) / (np.mean(r) + 1e-6)
            ])
            return np.array(features).reshape(1, -1)

        def forward_synthesis(self, clear_images):
            """前向合成:生成退化图像扩充数据集"""
            synthetic_pairs = []
            for clear_img in clear_images:
                for strength in [0.3, 0.5, 0.7, 1.0]:
                    degraded = clear_img.copy().astype(np.float32)
                    b, g, r = cv2.split(degraded)
                    b = b * np.exp(-0.5 * strength)
                    g = g * np.exp(-1.2 * strength)
                    r = r * np.exp(-2.0 * strength)
                    degraded = cv2.merge([
                        np.clip(b, 0, 255).astype(np.uint8),
                        np.clip(g, 0, 255).astype(np.uint8),
                        np.clip(r, 0, 255).astype(np.uint8)
                    ])
                    synthetic_pairs.append((degraded, clear_img))
            return synthetic_pairs

        def train(self, degraded_images, clear_images):
            """训练FbRF模型"""
            synthetic_pairs = self.forward_synthesis(clear_images)
            all_degraded = [d for d, _ in synthetic_pairs] + degraded_images
            all_clear = [c for _, c in synthetic_pairs] + clear_images

            X_train, y_b, y_g, y_r = [], [], [], []
            for deg, clear in zip(all_degraded, all_clear):
                features = self.extract_features(deg)
                X_train.append(features.flatten())
                b_c, g_c, r_c = cv2.split(clear)
                y_b.append(np.mean(b_c))
                y_g.append(np.mean(g_c))
                y_r.append(np.mean(r_c))

            X_train = np.array(X_train)
            self.rf_models['B'].fit(X_train, y_b)
            self.rf_models['G'].fit(X_train, y_g)
            self.rf_models['R'].fit(X_train, y_r)
            self.is_trained = True

        def predict(self, image):
            """色偏校正预测"""
            if not self.is_trained:
                raise ValueError("模型尚未训练")
            features = self.extract_features(image)
            b_target = self.rf_models['B'].predict(features)[0]
            g_target = self.rf_models['G'].predict(features)[0]
            r_target = self.rf_models['R'].predict(features)[0]

            b, g, r = cv2.split(image.astype(np.float32))
            b_mean, g_mean, r_mean = np.mean(b), np.mean(g), np.mean(r)
            gain_b = b_target / (b_mean + 1e-6)
            gain_g = g_target / (g_mean + 1e-6)
            gain_r = r_target / (r_mean + 1e-6)

            b_corrected = np.clip(b * gain_b, 0, 255)
            g_corrected = np.clip(g * gain_g, 0, 255)
            r_corrected = np.clip(r * gain_r, 0, 255)

            return cv2.merge([
                b_corrected.astype(np.uint8),
                g_corrected.astype(np.uint8),
                r_corrected.astype(np.uint8)
            ])


# ============================================================
# 第四/五部分:多重复合增强模型
# ============================================================

class MultiScaleFusionEnhancer:
    """基于多尺度N折融合的多重复合增强模型"""

    def __init__(self):
        self.classifier = UnderwaterImageClassifier()
        self.single_enhancer = SingleDegradationEnhancer()
        self.physical_model = UnderwaterImagingModel()

    def multi_scale_decomposition(self, image, n_scales=3):
        """多尺度图像分解"""
        scales = [image]
        current = image.copy()
        for _ in range(n_scales - 1):
            current = cv2.pyrDown(current)
            scales.append(current)
        return scales

    def physics_guided_enhance(self, image):
        """物理模型导向增强"""
        result = image.copy().astype(np.float32)
        b, g, r = cv2.split(result)
        b = np.clip(b * 1.1, 0, 255)
        g = np.clip(g * 1.3, 0, 255)
        r = np.clip(r * 2.0, 0, 255)
        result = cv2.merge([b, g, r]).astype(np.uint8)
        result = self.dehaze(result)
        return result

    def data_driven_enhance(self, image):
        """数据驱动增强"""
        result = self.simple_white_balance(image)
        gamma = 0.7
        result = np.power(result.astype(np.float32) / 255.0, gamma) * 255.0
        result = np.clip(result, 0, 255).astype(np.uint8)
        kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
        result = cv2.filter2D(result, -1, kernel)
        return result

    def hybrid_enhance(self, image):
        """混合增强"""
        physics = self.physics_guided_enhance(image)
        return self.data_driven_enhance(physics)

    def dehaze(self, image):
        """暗通道先验去雾"""
        min_channel = np.min(image, axis=2)
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
        dark_channel = cv2.erode(min_channel, kernel)
        flat_dark = dark_channel.flatten()
        top_pixels = int(len(flat_dark) * 0.001)
        if top_pixels == 0:
            top_pixels = 1
        indices = np.argpartition(flat_dark, -top_pixels)[-top_pixels:]
        flat_image = image.reshape(-1, 3)
        A = np.max(flat_image[indices], axis=0)
        t = 1 - 0.95 * dark_channel.astype(np.float32) / (np.max(A) + 1e-6)
        t = np.clip(t, 0.1, 1.0)
        result = np.zeros_like(image, dtype=np.float32)
        for i in range(3):
            result[:,:,i] = (image[:,:,i].astype(np.float32) - A[i]) / (t + 1e-6) + A[i]
        return np.clip(result, 0, 255).astype(np.uint8)

    def simple_white_balance(self, image):
        """简单白平衡"""
        result = image.copy().astype(np.float32)
        avg_b = np.mean(result[:,:,0])
        avg_g = np.mean(result[:,:,1])
        avg_r = np.mean(result[:,:,2])
        avg_gray = (avg_b + avg_g + avg_r) / 3.0
        result[:,:,0] *= avg_gray / (avg_b + 1e-6)
        result[:,:,1] *= avg_gray / (avg_g + 1e-6)
        result[:,:,2] *= avg_gray / (avg_r + 1e-6)
        return np.clip(result, 0, 255).astype(np.uint8)

    def fusion(self, images, weights=None):
        """多版本图像融合"""
        if weights is None:
            weights = [1.0 / len(images)] * len(images)
        result = np.zeros_like(images[0], dtype=np.float32)
        for img, w in zip(images, weights):
            result += img.astype(np.float32) * w
        return np.clip(result, 0, 255).astype(np.uint8)

    def enhance(self, image):
        """主增强流程"""
        category, scores = self.classifier.classify(image)
        scales = self.multi_scale_decomposition(image)
        enhanced_scales = []
        for scale in scales:
            versions = [
                self.physics_guided_enhance(scale),
                self.data_driven_enhance(scale),
                self.hybrid_enhance(scale)
            ]
            fused = self.fusion(versions)
            enhanced_scales.append(fused)

        result = enhanced_scales[-1]
        for i in range(len(enhanced_scales) - 2, -1, -1):
            result = cv2.pyrUp(result)
            if result.shape[:2] != enhanced_scales[i].shape[:2]:
                result = cv2.resize(result, (
                    enhanced_scales[i].shape[1], 
                    enhanced_scales[i].shape[0]
                ))
            result = cv2.addWeighted(result, 0.5, enhanced_scales[i], 0.5, 0)

        if category == 'blur':
            result = self.single_enhancer.enhance_blur(result)
        elif category == 'color_bias':
            result = self.data_driven_enhance(result)
        elif category == 'low_light':
            result = self.single_enhancer.enhance_low_light(result)

        return result, category


# ============================================================
# 评价指标模块
# ============================================================

class ImageQualityMetrics:
    """图像质量评价指标"""

    @staticmethod
    def psnr(img1, img2):
        """峰值信噪比"""
        mse = np.mean((img1.astype(np.float64) - img2.astype(np.float64)) ** 2)
        if mse == 0:
            return float('inf')
        return 20 * np.log10(255.0 / np.sqrt(mse))

    @staticmethod
    def uciqe(image):
        """水下彩色图像质量评价"""
        lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
        l, a, b = cv2.split(lab)
        chroma = np.sqrt(a.astype(np.float64)**2 + b.astype(np.float64)**2)
        sigma_c = np.std(chroma)
        conl = np.std(l) / (np.mean(l) + 1e-6)
        hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
        _, s, _ = cv2.split(hsv)
        mu_s = np.mean(s)
        return 0.4680 * sigma_c + 0.2745 * conl + 0.2576 * mu_s

    @staticmethod
    def uiqm(image):
        """水下图像质量度量"""
        b, g, r = cv2.split(image)
        rg = np.abs(r.astype(np.float64) - g.astype(np.float64))
        yb = np.abs(0.5 * (r.astype(np.float64) + g.astype(np.float64)) - b.astype(np.float64))
        rg_mean, rg_std = np.mean(rg), np.std(rg)
        yb_mean, yb_std = np.mean(yb), np.std(yb)
        uicm = np.sqrt(rg_std**2 + yb_std**2) + 0.3 * np.sqrt(rg_mean**2 + yb_mean**2)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
        sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
        uism = np.mean(np.sqrt(sobelx**2 + sobely**2))
        uiconm = np.std(gray) / (np.mean(gray) + 1e-6)
        return 0.0282 * uicm + 3.5753 * uism + 0.8852 * uiconm

    @staticmethod
    def sift_features(image):
        """SIFT特征点数量"""
        sift = cv2.SIFT_create()
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        keypoints, _ = sift.detectAndCompute(gray, None)
        return len(keypoints) if keypoints is not None else 0

    @classmethod
    def evaluate(cls, image, reference=None):
        """综合评估"""
        metrics = {
            'uciqe': cls.uciqe(image),
            'uiqm': cls.uiqm(image),
            'sift_features': cls.sift_features(image)
        }
        if reference is not None:
            metrics['psnr'] = cls.psnr(image, reference)
        return metrics


# ============================================================
# 主程序入口
# ============================================================

def main():
    print("=" * 70)
    print("水下图像增强系统")
    print("=" * 70)

    # 问题一:图像分类演示
    print("
【问题一】水下图像退化分类")
    print("-" * 50)

    classifier = UnderwaterImageClassifier()

    np.random.seed(42)
    test_images = {
        'normal': np.full((100, 100, 3), 128, dtype=np.uint8),
        'low_light': np.full((100, 100, 3), 30, dtype=np.uint8),
        'color_bias': np.full((100, 100, 3), [200, 100, 50], dtype=np.uint8),
        'blur': cv2.GaussianBlur(np.full((100, 100, 3), 128, dtype=np.uint8), (15, 15), 5)
    }

    for name, img in test_images.items():
        category, scores = classifier.classify(img)
        print(f"图像 '{name}' -> 分类: {category}")
        print(f"  亮度: {scores['brightness']['avg_brightness']:.2f}")
        print(f"  JSD: {scores['color']['jsd_score']:.4f}")
        print(f"  拉普拉斯方差: {scores['blur']['laplacian_var']:.2f}")

    # 问题二:物理模型演示
    print("
【问题二】Jaffe-McGlamery水下成像模型")
    print("-" * 50)

    model = UnderwaterImagingModel()
    degradation_models = model.build_degradation_models()

    for deg_type, info in degradation_models.items():
        print(f"退化类型: {deg_type}")
        print(f"  描述: {info['description']}")
        print(f"  主导因素: {info['dominant_factor']}")
        print(f"  特征: {info['characteristics']}")

    sample_img = test_images['color_bias']
    nap_result = model.noise_adversarial_preprocessing(sample_img)
    B = model.estimate_background_light(sample_img)
    print(f"
背景光估计: B={B['B']:.2f}, G={B['G']:.2f}, R={B['R']:.2f}")

    # 问题三:单一增强演示
    print("
【问题三】单一退化类型定制化增强")
    print("-" * 50)

    enhancer = SingleDegradationEnhancer()

    blur_img = test_images['blur']
    enhanced_blur = enhancer.enhance_blur(blur_img)
    print(f"模糊图像增强完成")

    low_img = test_images['low_light']
    enhanced_low = enhancer.enhance_low_light(low_img)
    print(f"低光照图像增强完成")

    fbrf = enhancer.ForwardBackwardRF()
    print(f"FbRF色偏校正模型已构建")

    # 问题四/五:多重复合增强
    print("
【问题四/五】多重复合增强模型")
    print("-" * 50)

    multi_enhancer = MultiScaleFusionEnhancer()
    print("多尺度N折融合增强模型已构建")

    # 评价指标
    print("
【评价指标】")
    print("-" * 50)

    for name, img in test_images.items():
        metrics = ImageQualityMetrics.evaluate(img)
        print(f"图像 '{name}':")
        print(f"  UCIQE: {metrics['uciqe']:.4f}")
        print(f"  UIQM: {metrics['uiqm']:.4f}")
        print(f"  SIFT特征点: {metrics['sift_features']}")

    # 增强前后对比
    print("
【增强效果对比】")
    print("-" * 50)

    for name, img in test_images.items():
        enhanced, cat = multi_enhancer.enhance(img)
        orig_metrics = ImageQualityMetrics.evaluate(img)
        enh_metrics = ImageQualityMetrics.evaluate(enhanced)
        print(f"图像 '{name}' (分类: {cat}):")
        print(f"  原始 UCIQE: {orig_metrics['uciqe']:.4f} -> 增强后: {enh_metrics['uciqe']:.4f}")
        print(f"  原始 UIQM: {orig_metrics['uiqm']:.4f} -> 增强后: {enh_metrics['uiqm']:.4f}")

    print("
" + "=" * 70)
    print("系统运行完成")
    print("=" * 70)


if __name__ == "__main__":
    main()
全部论文及程序请见下方" 只会建模 QQ名片" 点击QQ名片即可
相关推荐
学掌门13 小时前
数据分析师初级—中级—高级,每个阶段都需要学习什么?
大数据·学习·数据分析·数据分析师
Aloudata14 小时前
如何通过 NoETL 指标平台构建企业唯一指标计算中心
大数据·数据库·数据分析·指标平台
isNotNullX16 小时前
数据分析怎么做?数据分析全流程是什么?
数据挖掘·数据分析
数模竞赛Paid answer20 小时前
2025年MathorCup数学建模A题汽车风阻预测解题文档与程序
算法·数学建模·mathorcup
生信碱移1 天前
PACells:这个方法可以鉴定疾病/预后相关的重要细胞亚群,作者提供的代码流程可以学习起来了,甚至兼容转录组与 ATAC 两种数据类型!
人工智能·学习·算法·机器学习·数据挖掘·数据分析·r语言
ClkLog-开源埋点用户分析1 天前
在信创环境下,如何判断一套用户行为分析系统是否“真正可用”?
数据分析·开源·开源软件·用户画像·埋点系统
SelectDB1 天前
Doris & SelectDB for AI 实战:从基础 RAG 到知识图谱增强的完整实现
数据库·人工智能·数据分析
AI科技星1 天前
人类首张【全域数学公理体系】黑洞内部结构图—基于「0-1-∞」三元本源的全维深度解析
人工智能·算法·机器学习·数学建模·数据挖掘·量子计算
SL-staff1 天前
中小企业 BI 选型:帆软、Power BI、JVS-BI 性价比与架构对比
数据分析·数据可视化·powerbi·帆软·bi工具·部署架构·jvs-bi