SSR / MSR 图像增强

Retinex 的核心假设:

I(x,y) = 光照L(x,y) × 反射率R(x,y)

增强的本质是:用高斯模糊估计低频光照L,然后在对数域把L"减掉",得到细节反射R,最后再做增益/偏置拉伸。


一、完整可运行代码

1.1 主文件:retinex_ssr_msr.m

matlab 复制代码
%% SSR / MSR 图像增强(单尺度 & 多尺度 Retinex)
% 不使用任何搜索/下载工具箱函数
clear; clc; close all;

%% 1. 读图
img = imread('lena.png');   % ← 换成你的图
if isa(img,'uint8'), img = double(img)/255; end
if size(img,3)==1, img = repmat(img,[1 1 3]); end  % 灰度伪造三通道显示用

%% 2. 参数
sigma_ssr = 80;              % SSR 高斯尺度(大=光照更平滑,去雾感更强;小=保留更多局部)
sigmas_msr = [15, 80, 250]; % MSR 三个尺度(小/中/大)
weights_msr = [1 1 1]/3;     % 权重和=1

gain = 1.0;                  % 最终对比度拉伸增益
bias  = 0.0;                  % 亮度偏移(-0.2~0.3)
epsilon = 1e-6;

%% 3. SSR
img_ssr = single_scale_retinex(img, sigma_ssr, epsilon);

%% 4. MSR
img_msr = multi_scale_retinex(img, sigmas_msr, weights_msr, epsilon);

%% 5. 后处理:增益/offset + 色调再现(简单S形可选)
img_ssr = retinex_postprocess(img_ssr, gain, bias);
img_msr = retinex_postprocess(img_msr, gain, bias);

%% 6. 显示
figure('Color','w','Position',[80 80 1300 430]);
subplot(1,3,1); imshow(img);   title('原图');
subplot(1,3,2); imshow(img_ssr); title(sprintf('SSR  σ=%.0f',sigma_ssr));
subplot(1,3,3); imshow(img_msr); title('MSR  [15,80,250]');
sgtitle('SSR / MSR Retinex 图像增强(纯手写)','FontSize',13,'FontWeight','bold');

%% 直方图对比(可选)
figure('Color','w','Position',[80 530 1300 260]);
subplot(1,3,1); imhist(uint8(img*255)); title('原图直方图'); xlim([0 255]); grid on
subplot(1,3,2); imhist(uint8(img_ssr*255)); title('SSR 直方图'); xlim([0 255]); grid on
subplot(1,3,3); imhist(uint8(img_msr*255)); title('MSR 直方图'); xlim([0 255]); grid on

1.2 SSR 核心函数:single_scale_retinex.m

matlab 复制代码
function out = single_scale_retinex(img, sigma, eps_val)
% SSR: log(R) = log(I) - log(L),  L = I * Gσ
% 输入 img H×W×3 double [0,1]
% 输出 out 同尺寸,double,可正可负(后续需后处理)

[H,W,C] = size(img);
out = zeros(H,W,C);

for c = 1:C
    I = img(:,:,c);
    I = max(I, eps_val);

    % 高斯滤波估计光照L(手工二维高斯,无fspecial/fspecial调用)
    L = gaussian_blur_2d(I, sigma);
    L = max(L, eps_val);

    % 对数域分离
    out(:,:,c) = log(I) - log(L);
end
end

1.3 手工二维高斯模糊(最核心:你不让我用imgaussfilt/fspecial也完全成立)

matlab 复制代码
function J = gaussian_blur_2d(I, sigma)
% 可分离二维高斯:先行再列(稳定+快)
% I: H×W double
[H,W] = size(I);
half = ceil(3*sigma);
x = (-half:half);
g1 = exp(-0.5*(x/sigma).^2);
g1 = g1 / sum(g1);

% 行方向
Jtmp = zeros(H,W);
for r = 1:H
    Jtmp(r,:) = conv(Jtmp(r,:), g1, 'same');
end
% 列方向
J = zeros(H,W);
for c = 1:W
    J(:,c) = conv(Jtmp(:,c), g1, 'same');
end
end

如果你担心边界振铃,把 conv(x,g1,'same') 改成手动镜像填充(pad)再 conv2(...,'valid') 也行;但对Retinex来说 'same' 一般够用。


1.4 MSR 多尺度加权平均:multi_scale_retinex.m

matlab 复制代码
function out = multi_scale_retinex(img, sigmas, weights, eps_val)
% MSR: 每个尺度做SSR,然后加权求和
% weights 和=1

[H,W,C] = size(img);
out = zeros(H,W,C);
N = length(sigmas);

for s = 1:N
    tmp = single_scale_retinex(img, sigmas(s), eps_val);
    out = out + weights(s) * tmp;
end
end

1.5 后处理(把Retinex的输出拉回0,1并给对比度)

matlab 复制代码
function out = retinex_postprocess(R, gain, bias)
% R: Retinex输出(可能负,动态范围不一定好看)
% 策略:逐通道做 min-max stretch(最稳)
out = R;
[H,W,C] = size(R);

for c = 1:C
    rc = R(:,:,c);
    mn = min(rc(:)); mx = max(rc(:));
    if mx-mn < 1e-8
        out(:,:,c) = 0.5;
    else
        out(:,:,c) = (rc - mn)/(mx - mn);
    end
end

% 可选:轻微Sigmoid防止过冲(去掉注释启用)
% out = 1./(1+exp(-gain*(out-0.5))) * 1.0; 

% 最后线性增益/偏置
out = min(max(out*gain + bias, 0), 1);
end

二、运行效果你会看到什么

版本 视觉效果 适合场景
SSR(σ大≈80~120) 像"去不均匀光照/去雾" 背光人脸、内窥镜、隧道监控
SSR(σ小≈15~30) 更像锐化+微对比增强 纹理增强
MSR(15/80/250) 同时保留细纹理 + 压制大尺度光照 最通用,但颜色会偏一点

颜色偏的原因:上面是对 RGB 三通道各自独立做 log(I)-log(L),L 的尺度是按亮度走的,但 R/G/B 的增益并不全等 ⇒ 色相漂移。

参考代码 SSR单尺度图像增强 MSR多尺度Retinex图像增强模型 www.youwenfan.com/contentcsv/81227.html

三、改进版:在 Intensity 通道 做 Retinex

把 RGB→HSV/HSI,只增强 V/I,再回去:

matlab 复制代码
function out = retinex_on_intensity(img, sigma, eps_val, gain, bias)
% img: H×W×3 double [0,1]
% 用 HSV 的 V 通道(最安全)
[H,W,C] = size(img);
rgb = img;

% RGB→HSV 手工(不用rgb2hsv)
V = max(img,[],3);                    % intensity(最朴素;更好用 I=0.299R+0.587G+0.114B)
% 若你坚持用加权亮度:
% I = 0.299*img(:,:,1)+0.587*img(:,:,2)+0.114*img(:,:,3);

I = V; I = max(I,eps_val);
L = gaussian_blur_2d(I, sigma); L = max(L,eps_val);
R = log(I) - log(L);                  % 反射率对数

% 拉回[0,1]
mn=min(R(:)); mx=max(R(:));
Rmap = (R-mn)/(mx-mn+eps_val);

% 重新上色:把Rmap当成新的V缩放回原色
out = img;
scale = Rmap ./ (I + eps_val);       % 关键:逐像素乘回原通道(保色调)
for c=1:3
    out(:,:,c) = min(max(out(:,:,c) .* scale, 0),1);
end
out = min(max(out*gain+bias,0),1);
end
相关推荐
TCW11211 小时前
AI底层系列:用C++实现线性代数的公式推导与算法设计-6.线性方程组的解集
c++·人工智能·算法
古城小栈1 小时前
Python 的主流Ai框架为什么优先适配 Linux 系统?
linux·人工智能·python
财经资讯数据_灵砚智能1 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年6月15日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能
暮云星影1 小时前
瑞芯微rk3588利用Rockchip NPU运行大语言模型(LLM)
arm开发·人工智能·语言模型·自然语言处理
ujainu小1 小时前
CANN ops-transformer:编译和运行 FlashAttention 示例
人工智能·深度学习·transformer
Xiaofeng36931 小时前
硬核编码与推理对决:Gemini 3.5 Flash vs GPT-5.5 真实能力横向测评
人工智能·gpt
邵宇然1 小时前
编译优化技术全解:从 LLVM Pass 到链接时优化的性能提升路径
人工智能
宝贝儿好1 小时前
【LLM】第一章:知识体系框架概览
人工智能·深度学习·机器学习·自然语言处理
DS随心转插件2 小时前
智谱清言化学式粘贴后变形如何修复?AI 导出鸭从根源解决化学公式跨文档乱码难题
人工智能·ai·豆包·deepseek·ai导出鸭
写点啥呢2 小时前
车机 Android 开机优化复盘:我怎么和 AI 一起把问题定位到 SystemUI
android·人工智能