一、McCann99 Retinex

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

严格的限制,要求可表示成 ,且 

上述限制来源于金字塔模型的结构要求,由于要对输入图像进行下采样,金字塔中上层低分辨率图像的宽分别为下

层高分辨率图像的1/2,顶层(第n层)大小为,底层(第0层)为原图像。金字塔结构如下图所示。

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

措施,此处暂不考虑。

算法从顶层开始,将每个像素与其8领域像素比较,估计每个像素点的亮度值(lightness),比较的迭代次数nIterator

由用户决定,每次迭代有四步操作:比例(ratio)、乘积(product)、重置(reset)、平均(average)。随着迭代次数的增

大,像素受到邻域的影响范围就会扩大。每层计算结束后对该层所得图像进行插值运算,使其尺寸与下一层相同,并

将插值结果作为下一层处理的初始值。对下一层进行相同操作,这样自顶向下直至金字塔底层得到最终增强结果。

对每金字塔每一层:设OP为上一步迭代的乘积;NP为当前迭代的乘积;IP为中间乘积结果;R为该层输入图像;符号

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

变量初始化:

金字塔层数由原始图像尺寸决定,大小为 ,层数为n+1;

OP初始尺寸为,各像素值一般设为原始图像中的最大值;

R:第k层输入图为像原始图像的下采样,大小为

迭代次数nIterator一般设为4;

图像金字塔模型

 二、Matlab实现

function Test()
ImOriginal=imread('fig5.tif');
[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(nrows,1) OP zeros(nrows,1)]; % pad OP with additional columns
OPE = [zeros(1,ncols+2); OPE; zeros(1,ncols+2)]; % and rows
RRE = [RR(:,1) RR RR(:,end)]; % pad RR with additional columns
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

测试结果:

输入

输出

注:输出时只是简单的进行线性拉伸,使得灰度值落在[0-255],没有使用更好调整方法。

参考:

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.

版权声明:本文为博主原创文章,未经博主允许不得转载。

Retinex系列之McCann99 Retinex 分类: 图像处理 Matlab 2014-12-03 11:27 585人阅读 评论(0) 收藏的更多相关文章

  1. Matlab调用C程序 分类: Matlab c/c++ 2015-01-06 19:18 464人阅读 评论(0) 收藏

    Matlab是矩阵语言,如果运算可以用矩阵实现,其运算速度非常快.但若运算中涉及到大量循环,Matlab的速度令人难以忍受的.当必须使用for循环且找不到对应的矩阵运算来等效时,可以将耗时长的函数用C ...

  2. 分类算法简介 分类: B10_计算机基础 2015-03-09 11:08 257人阅读 评论(0) 收藏

    一.决策树 决策树是用于分类和预测的主要技术之一,决策树学习是以实例为基础的归纳学习算法,它着眼于从一组无次序.无规则的实例中 推理出以决策树表示的分类规则.构造决策树的目的是找出属性和类别间的关系, ...

  3. Train Problem I 分类: HDU 2015-06-26 11:27 10人阅读 评论(0) 收藏

    Train Problem I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  4. Makefile 入门与基本语法 分类: C/C++ ubuntu 2015-05-18 11:16 466人阅读 评论(0) 收藏

    在我看来,学会写简单的Makefile,阅读较复杂的makefile,是每一个Linux程序员都必须拥有的基本素质.Makefile可以自动识别哪些源文件被更改过,需要重新编译,那些不需要.从而节省大 ...

  5. Javascript图片预加载详解 分类: JavaScript HTML+CSS 2015-05-29 11:01 768人阅读 评论(0) 收藏

    预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布 ...

  6. OC基础:继承.初始化方法,便利构造器 分类: ios学习 OC 2015-06-16 19:27 84人阅读 评论(0) 收藏

    继承: 1.单向继承,一个类只能有一个父类,一个父类可以有多个子类. 2.单向继承,基类(根类)是OSObject 3.子类可以继承父类的属性和方法 当父类的方法不满足子类的需求时,子类可以重写父类的 ...

  7. HIVE快速入门 分类: B4_HIVE 2015-06-06 11:27 59人阅读 评论(0) 收藏

    (一)简单入门 1.创建一个表 create table if not exists ljh_emp( name string, salary float, gender string) commen ...

  8. Gora官方文档之二:Gora对Map-Reduce的支持 分类: C_OHTERS 2015-01-31 11:27 232人阅读 评论(0) 收藏

    参考官方文档:http://gora.apache.org/current/tutorial.html 项目代码见:https://code.csdn.net/jediael_lu/mygoradem ...

  9. javascript中定义事件的三种方式 分类: C1_HTML/JS/JQUERY 2014-08-07 10:27 634人阅读 评论(0) 收藏

    在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 3.在javascipt中,使 ...

随机推荐

  1. 【APUE】进程间通信之共享存储(mmap函数)

    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只 ...

  2. 解决Win7 64bit + VS2013 使用opencv时出现提“应用程序无法正常启动(0xc000007b)”错误

    应用程序无法正常启动(0xc000007b) 记得以前也遇到过这样的问题:网上的解决方法就是修复什么 今天配置opencv2.4.8+vs2013的时候,发现用老版本的程序是不是都会出现这样的现象啊! ...

  3. IntelliJ 中类似于Eclipse ctrl+o的是ctrl+F12

    IntelliJ 中类似于Eclipse ctrl+o的是ctrl+F12 学习了:https://blog.csdn.net/sjzylc/article/details/47979815

  4. CentOS 7下安装Logstash ELK Stack 日志管理系统(下)

    修改防火墙,对外开放tcp/5601 [root@elk elk]# firewall-cmd --permanent --add-port=5601/tcpSuccess[root@elk elk] ...

  5. 我所写的CNN框架 VS caffe

    我所写的CNN框架 VS caffe 一个月前.自己模仿caffe实现了一个卷积神经网络的框架. 同样点 1无缝支持CPU和GPU模式,GPU模式使用cuda实现. 不同点 1我的CNN不依赖与不论什 ...

  6. udhcp源码详解(二)--转

    定义的数据结构对于C程序的重要性,不言而喻.面向对象设计的程序是一个个对象的集合,而面向过程语言设计的程序则是数据结构与算法的集合. 下面来分析的是dhcp server中的定义结构体: 1).在pa ...

  7. NS3网络仿真(12): ICMPv4协议

    快乐虾 http://blog.csdn.net/lights_joy/ 欢迎转载,但请保留作者信息 ICMP的全称是 Internet ControlMessage Protocol . 其目的就是 ...

  8. su: /bin/bash: Permission denied带来的疑惑

    >客户一个oracle突然当机了,由于业务启动,客户下意识的重启了服务器,系统是起来了,准备切换到oracle用户下启动数据库,可以怎么都无法su切换,真是火上浇油呀,描述如下: 在root用户 ...

  9. centOS安装mysql---glibc方式

    写在前面: 首先,centos是自己集成mysql的.但是我要用的服务器人家没给装. 其次,centos是可以yum安装mysql的,我很高兴而且轻松的用yum把mysql安装上了.但是,运行的时候很 ...

  10. 日元兑换——国内兑换需要护照和签证,国外的机场有兑换ATM

    在中国换日元:在中国的商业银行都可以换取日元,但是换汇者必须持有护照.签证等材料.换汇的汇率是按照即时汇率进行结算,如是现钞则按钞买价兑换,另外还要收取0.5%的手续费. 在日本换日元:除了在日本银行 ...