# Retinex系列之McCann99 Retinex

McCann99利用金字塔模型建立对图像的多分辨率描述,自顶向下逐层迭代，提高增强效率。对输入图像的长宽有

McCann99算法对输入图像的尺寸要求过于严格，以至于大部分图像不能直接用此算法进行增强，后续有很多改进

*表示重置操作。其中对于每个像素执行的四步操作使用和Frankle-McCann相同的公式：

$NP(x,y)=\sqrt{OP(x,y)IP^{*}(x,y)}=\sqrt{OP(x,y)[OP(xs,ys)\frac{R(x,y)}{R(xs,ys)}]^{*}}$

OP初始尺寸为$rows\times cols$，各像素值一般设为原始图像中的最大值；

R：第k层输入图为像原始图像的下采样，大小为$nrows\cdot 2^{n-k}\times ncols\cdot2^{n-k}$

二、Matlab实现

function Test()
[m,n,z] = size(ImOriginal);
ImOut = zeros(m,n,z);
for i = 1:z
ImChannel = log(double(ImOriginal(:,:,i))+eps);
ImOut(:,:,i)=retinex_mccann99(ImChannel,4);
ImOut(:,:,i)=exp(ImOut(:,:,i));
a=min(min(ImOut(:,:,i)));
b=max(max(ImOut(:,:,i)));
ImOut(:,:,i)=((ImOut(:,:,i)-a)/(b-a))*255;
end
ImOut=uint8(ImOut);
figure(1);
imshow(ImOriginal);
figure(2);
imshow(ImOut);

function Retinex = retinex_mccann99(L, nIterations)
% INPUT:  L           - logarithmic single-channel intensity image to be processed
%         nIterations - number of Retinex iterations
%
% OUTPUT: Retinex     - raw Retinex output
global OPE RRE Maximum
[nrows ncols] = size(L);                             % get size of the input image
nLayers = ComputeLayers(nrows, ncols);               % compute the number of pyramid layers
nrows = nrows/(2^nLayers);                           % size of image to process for layer 0
ncols = ncols/(2^nLayers);
if (nrows*ncols > 25)                                % not processing images of area > 25
error('invalid image size.')                       % at first layer
end
Maximum = max(L(:));                                 % maximum color value in the image
OP = Maximum*ones([nrows ncols]);                    % initialize Old Product
for layer = 0:nLayers
RR = ImageDownResolution(L, 2^(nLayers-layer));   % reduce input to required layer size
OPE = [zeros(1,ncols+2); OPE; zeros(1,ncols+2)];  % and rows
RRE = [RRE(1,:); RRE; RRE(end,:)];                % and rows

for iter = 1:nIterations
CompareWithNeighbor(-1, 0);                     % North
CompareWithNeighbor(-1, 1);                     % North-East
CompareWithNeighbor(0, 1);                      % East
CompareWithNeighbor(1, 1);                      % South-East
CompareWithNeighbor(1, 0);                      % South
CompareWithNeighbor(1, -1);                     % South-West
CompareWithNeighbor(0, -1);                     % West
CompareWithNeighbor(-1, -1);                    % North-West
end

NP = OPE(2:(end-1), 2:(end-1));
OP = NP(:, [fix(1:0.5:ncols) ncols]);             %%% these two lines are equivalent with
OP = OP([fix(1:0.5:nrows) nrows], :);             %%% OP = imresize(NP, 2) if using Image
nrows = 2*nrows; ncols = 2*ncols;                 % Processing Toolbox in MATLAB
end
Retinex = NP;

%将当前像素与八邻域比较
function CompareWithNeighbor(dif_row, dif_col)
global OPE RRE Maximum
% Ratio-Product operation
IP = OPE(2+dif_row:(end-1+dif_row), 2+dif_col:(end-1+dif_col)) + ...
RRE(2:(end-1),2:(end-1)) - RRE(2+dif_row:(end-1+dif_row), 2+dif_col:(end-1+dif_col));
IP(IP > Maximum) = Maximum;                          % The Reset step

% ignore the results obtained in the rows or columns for which the neighbors are undefined
%因OPE边界处填充了0，故IP对应的边界处结果无意义，直接置成原值
if (dif_col == -1) IP(:,1) = OPE(2:(end-1),2); end
if (dif_col == +1) IP(:,end) = OPE(2:(end-1),end-1); end
if (dif_row == -1) IP(1,:) = OPE(2, 2:(end-1)); end
if (dif_row == +1) IP(end,:) = OPE(end-1, 2:(end-1)); end

NP = (OPE(2:(end-1),2:(end-1)) + IP)/2;              % The Averaging operation
OPE(2:(end-1), 2:(end-1)) = NP;

%power:nrows,ncols的最大公约数且是2的整数次方
function Layers = ComputeLayers(nrows, ncols)
power = 2^fix(log2(gcd(nrows, ncols)));              % start from the Greatest Common Divisor
while(power > 1 && ((rem(nrows, power) ~= 0) || (rem(ncols, power) ~= 0)))
power = power/2;                                  % and find the greatest common divisor
end                                                  % that is a power of 2
Layers = log2(power);

%下采样，将blocksize*blocksize区域映射为一个像素点
function Result = ImageDownResolution(A, blocksize)
[rows, cols] = size(A);                              % the input matrix A is viewed as
result_rows = rows/blocksize;                        % a series of square blocks
result_cols = cols/blocksize;                        % of size = blocksize
Result = zeros([result_rows result_cols]);
for crt_row = 1:result_rows                          % then each pixel is computed as
for crt_col = 1:result_cols                       % the average of each such block
Result(crt_row, crt_col) = mean2(A(1+(crt_row-1)*blocksize:crt_row*blocksize, ...
1+(crt_col-1)*blocksize:crt_col*blocksize));
end
end


http://www.cnblogs.com/sleepwalker/p/3676600.html

[1] J.J. McCann, “LessonsLearned from Mondrians Applied to Real Images and Color Gamuts”, Proc.IS&T/SID Seventh Color Imaging Conference, pp. 1-8, 1999.

[2] Brian Funt, FlorianCiurea, and John McCann "Retinex in Matlab," Proceedings of the IS&T/SIDEighth Color Imaging Conference: Color Science, Systems and Applications, 2000.

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客