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
相关推荐
lpfasd1235 分钟前
2026年第30周科技社区趋势周报:开放权重之争与AI Agent的破局
人工智能·科技
佛光芳林2 小时前
AI 情报局:用 PowerMem + SeekDB 做一个多 Agent 记忆小游戏
人工智能
通问AI2 小时前
2026年AI短剧技术现状:全链路AIGC生产已达95%,但用户完播率不足15%
人工智能·aigc
_Jimmy_2 小时前
Agent引用数据库知识过时的增量同步方案
人工智能·python·langchain
qq_454245032 小时前
Systemprompt 体系全览:形式化公理驱动的分层系统设计
人工智能
大龄码农有梦想2 小时前
传统的 BPMN 工作流审批和 AI 工作流有什么区别?
人工智能·流程引擎·工作流·ai agent·ai工作流·审批流·智能体平台
DO_Community3 小时前
Claude Opus 5 现已上线 DigitalOcean AI 推理云
人工智能·llm·agent·claude
幸福指北3 小时前
🚀 开源了,一个人 + AI 肝出一个 AI 终端 | AShell 技术分享
运维·人工智能·ai·终端
可以飞的话3 小时前
一、机器学习概述
人工智能·机器学习
sunneo3 小时前
磐石2.0发布,科学建模新突破
人工智能