发在CVPR2015上的一篇文章,读起来并不是很困难,思路也比较纯粹。作者也开源了代码,在这里下载:http://pages.iai.uni-bonn.de/frintrop_simone/vocus2.html问题是,作者的代码依赖于Boost C++ Library,但是我对这个库并不是很熟悉,配置起来可能不是那么方便。所以我根据自己的理解,用Matlab重写了一下,看起来效果还可以,希望能对需要的人有所帮助。需要指出的是,对于一些细节的理解可能不准确,比如说八度的个数,每个八度的层数,生成金字塔特征的过程等。因此,该代码只做测试用,未与原始C++版本代码对照修正,如果需要与论文方法做比较,请依据作者原始代码进行测评。
GetFeatureChannels.m
function [Intensity RG BY] = GetFeatureChannels( Img )
if(length(size(Img))~=3)
disp('Input image must be a color image with RGB 3 channels!');
return;
end
R=Img(:,:,1);
G=Img(:,:,2);
B=Img(:,:,3);
Intensity=(R+G+B)/3;
RG=R-G;
BY=B-(R+G)/2;
end
BuildMultiScaleTwinPyr.m
function [center_pyramid surround_pyramid] = BuildMultiScaleTwinPyr( input_image_channel,octave_num,layer_num,sig_center,sig_surround )
% 第几个八度(o)和八度中的第几层(s)两个变量构成了高斯金字塔的尺度空间。
% 一个八度中图像的长和宽是相等的,即变量o控制的是塔中尺寸这个尺度;
% s控制的是一个八度中不同的模糊程度。
center_pyramid=cell(octave_num,layer_num);
surround_pyramid=cell(octave_num,layer_num);
tmpimg=input_image_channel;
for o=0:octave_num-1
for s=0:layer_num-1
sig_total=power(2.0,double(o)+double(s)/double(layer_num-1))*sig_center;
gaussFilter=fspecial('gaussian',[5 5],sig_total);
center_pyramid{o+1,s+1}=double(imfilter(tmpimg,gaussFilter,'replicate'));
sig_ratio=sqrt(sig_surround*sig_surround-sig_center*sig_center);
ratioFilter=fspecial('gaussian',[5 5],sig_ratio);
surround_pyramid{o+1,s+1}=double(imfilter(center_pyramid{o+1,s+1},ratioFilter,'replicate'));
end
tmpimg=imresize(tmpimg,[size(tmpimg,1)/2 size(tmpimg,2)/2]);
end
end
FeatureFusion.m
function FeatureMap = FeatureFusion( ContrastPyr )
%ContrastPyr should be in CELL format. Each row represents an OCTAVE with
%multiple layers (in our setup, we set 3 layers in one octave). FeatureMap
%should be the same size as elements in first row of ContrastPyr, that is,
%FeatureMap is the same size as original input image. Consequently, before
%fusing ContrastPyr, we should unify(enlarge) contrast maps to the same
%size, i.e., size of original input image.
[height width]=size(ContrastPyr{1,1}); %standard size
FeatureMap=zeros(height,width);
[m n]=size(ContrastPyr);
SameSizeMap=cell(m,n);
for i=1:m % Remain first row of ContrastPyr unchanged
for j=1:n
if(i==1)
SameSizeMap{i,j}=ContrastPyr{i,j};
else
SameSizeMap{i,j}=imresize(ContrastPyr{i,j},[height width],'bicubic');
end
end
end
for i=1:m
for j=1:n
FeatureMap=FeatureMap+SameSizeMap{i,j};
end
end
end
Normalize.m
function OutImg = Normalize(InImg)
ymax=255;ymin=0;
xmax = max(max(InImg)); %求得InImg中的最大值
xmin = min(min(InImg)); %求得InImg中的最小值
OutImg = round((ymax-ymin)*(InImg-xmin)/(xmax-xmin) + ymin); %归一化并取整
end
Main.m
clc;
clear;
% Path setting
inputImgPath = 'Imgs'; % input image path
resSalPath = 'SAL_MAP'; % result path
if ~exist(resSalPath, 'file')
mkdir(resSalPath);
end
addpath(genpath(inputImgPath));
% Parameter setting
octave_num=5; %5个八度
layer_num=3; %每个八度下3层
sig_center=3;
sig_surround=13;
%% Create twin pyramids
imgFiles = dir(inputImgPath);
for indImg = 1:2:length(imgFiles)-2
% read image
imgPath = fullfile(inputImgPath, imgFiles(indImg+2).name);
img= imread(imgPath);
[Intensity RG BY]=GetFeatureChannels(img);
% Build twin pyramids for Internsity
[InCenterPyr InSurroundPyr] = BuildMultiScaleTwinPyr(Intensity,octave_num,layer_num,sig_center,sig_surround);
% Build twin pyramids for RG
[RGCenterPyr RGSurroundPyr] = BuildMultiScaleTwinPyr(RG,octave_num,layer_num,sig_center,sig_surround);
% Build twin pyramids for BY
[BYCenterPyr BYSurroundPyr] = BuildMultiScaleTwinPyr(BY,octave_num,layer_num,sig_center,sig_surround);
%% Create contrast pyramids
[m n]=size(InCenterPyr);
InOnOff=cell(m,n);
InOffOn=cell(m,n);
RGOnOff=cell(m,n);
RGOffOn=cell(m,n);
BYOnOff=cell(m,n);
BYOffOn=cell(m,n);
for i=1:m
for j=1:n
InOnOff{i,j}=InCenterPyr{i,j}-InSurroundPyr{i,j};
tmp=InOnOff{i,j};
InOnOff{i,j}(find(tmp(:)<0))=0;
InOffOn{i,j}=InSurroundPyr{i,j}-InCenterPyr{i,j};
tmp=InOffOn{i,j};
InOffOn{i,j}(find(tmp(:)<0))=0;
RGOnOff{i,j}=RGCenterPyr{i,j}-RGSurroundPyr{i,j};
tmp=RGOnOff{i,j};
RGOnOff{i,j}(find(tmp(:)<0))=0;
RGOffOn{i,j}=RGSurroundPyr{i,j}-RGCenterPyr{i,j};
tmp=RGOffOn{i,j};
RGOffOn{i,j}(find(tmp(:)<0))=0;
BYOnOff{i,j}=BYCenterPyr{i,j}-BYSurroundPyr{i,j};
tmp=BYOnOff{i,j};
BYOnOff{i,j}(find(tmp(:)<0))=0;
BYOffOn{i,j}=BYSurroundPyr{i,j}-BYCenterPyr{i,j};
tmp=BYOffOn{i,j};
BYOffOn{i,j}(find(tmp(:)<0))=0;
end
end
%% FeatureMaps
InOnOffFusion=FeatureFusion(InOnOff);
InOffOnFusion=FeatureFusion(InOffOn);
RGOnOffFusion=FeatureFusion(RGOnOff);
RGOffOnFusion=FeatureFusion(RGOffOn);
BYOnOffFusion=FeatureFusion(BYOnOff);
BYOffOnFusion=FeatureFusion(BYOffOn);
%% FeatureMaps Fusion
IntensityFeature=Normalize((InOnOffFusion+InOffOnFusion)/2);
RGFeature=Normalize((RGOnOffFusion+RGOffOnFusion)/2);
BYFeature=Normalize((BYOnOffFusion+BYOffOnFusion)/2);
%% Generate Saliency Map
FeatureMap=Normalize((IntensityFeature+RGFeature+BYFeature)/3);
figure(indImg);
subplot(121);
imshow(img,[]);
title('Original Image');
subplot(122);
imshow(FeatureMap,[]);
title('Saliency Map');
pause(2);
close(figure(indImg));
end
再次提醒,该代码可能不能准确反映论文原始意图,仅做测试使用,顺便可能对需要的人有所启发。贴几张效果图
有问题可联系 jzwangATbjtuDOTeduDOTcn讨论交流。