% --------------------------------------------------------------------
% Demo_LASC_voc07 code to perform an example code of image classification
% on PASCAL VOC 2007 database.
% For theoretical and technical details, please refer to the following paper:
%
% Peihua Li, Xiaoxiao Lu, Qilong Wang, "From Dictionary of Visual 
% Words to Subspaces: Locality-constrained Affine Subspace Coding", CVPR 2015.
%
% Please cite the paper above if you use the code.
% For questions, please contact: Xiaoxiao Lu (Email: shaw@mail.dlut.edu.cn)
%                                Qilong Wang (Email: wangqilong.415@163.com)
%                                Peihua Li   (Email: peihuali at dlut dot edu dot cn)
%
% The software is provided ''as is'' and without warranty of any kind,
% express, implied or otherwise, including without limitation, any
% warranty of merchantability or fitness for a particular purpose.

% --------------------------------------------------------------------
%                                                    Parameter settings
% --------------------------------------------------------------------
clear
% if matlabpool('size') == 0
%     matlabpool local;        % matlabpool local 2; if your RAM is less than 32G
% end
S = RandStream('mt19937ar','seed',1024);
RandStream.setGlobalStream(S);
total_start_time = round(clock);
run(fullfile(fileparts(which(mfilename)), 'VLFeat', 'toolbox', 'vl_setup.m')) ;

opts.dataset = 'voc07';
opts.prefix = 'lasc' ;
opts.encoderParams = {...
    'type', opts.prefix, ... 
    'numWords',256, ...
    'numPcaDimensions', 64, ...
    'layouts', {'1x1','3x1'}, ...
    'extractorFn', @(x) getDenseSIFT(x, 'step', 4, 'scales', 2.^(0:-0.5:-2))};

opts.C = 10;
opts.seed = 1;
opts.kernel = 'linear';
opts.dataDir = 'data';
opts.datasetDir = fullfile(opts.dataDir, opts.dataset) ;
opts.resultDir = fullfile(opts.dataDir, [opts.dataset '-' opts.prefix]) ;
opts.imdbPath = fullfile(opts.resultDir, 'imdb.mat') ;
opts.encoderPath = fullfile(opts.resultDir, 'encoder.mat') ;
opts.cacheDir = fullfile(opts.resultDir, 'cache') ;
vl_xmkdir(opts.cacheDir) ;
addpath(fullfile(pwd, 'svm'));
addpath(fullfile(pwd, 'setup'));
addpath(fullfile(pwd, 'encode'));
imdb = setupVoc(opts.datasetDir, 'edition', '2007') ;


fprintf('****************************************************************\n');
fprintf('Generating the code book... \n');
fprintf('****************************************************************\n');
start_time = round(clock);

if exist(opts.encoderPath, 'file')
  encoder = load(opts.encoderPath) ;
else
  numTrain = 5000 ;
  train_idx = vl_colsubset(find(imdb.images.set <= 2), numTrain, 'uniform') ;
  encoder = trainEncoder(fullfile(imdb.imageDir,imdb.images.name(train_idx)), opts.encoderParams{:}) ;
  save(opts.encoderPath, '-struct', 'encoder') ;
end
end_time = round(clock);
elapsed_time = end_time - start_time;
fprintf('Time taken: %5d days %5d hours %5d minutes %5d seconds\n\n', elapsed_time(3), elapsed_time(4), elapsed_time(5), elapsed_time(6));


fprintf('****************************************************************\n');
fprintf('Encoding the images... \n');
fprintf('****************************************************************\n');
start_time = round(clock);

encodeImage(encoder, fullfile(imdb.imageDir, imdb.images.name), 'cacheDir', opts.cacheDir) ; 
end_time = round(clock);
elapsed_time = end_time - start_time;
fprintf('Time taken: %5d days %5d hours %5d minutes %5d seconds\n\n', elapsed_time(3), elapsed_time(4), elapsed_time(5), elapsed_time(6));


fprintf('****************************************************************\n');
fprintf('Runing svm classification... \n');
fprintf('****************************************************************\n');
start_time = round(clock);

if isfield(imdb.images, 'class')
  classRange = unique(imdb.images.class) ;
else
  classRange = 1:numel(imdb.classes.imageIds) ;
end
iter_num = 1;
accuracies = zeros(iter_num, 1);
for iter = 1:iter_num
    imdb = setupVoc(opts.datasetDir, 'edition', '2007') ;
    train_idx = find(imdb.images.set <= 2) ;
    test_idx = find(imdb.images.set == 3) ;
    accuracies(iter) = svm_vlfeat(imdb, opts, classRange, train_idx, test_idx);
    fprintf('traintest: Iteration %2d  accuracy: %5.2f\n', iter,  accuracies(iter));  
end
end_time = round(clock);
elapsed_time = end_time - start_time;
fprintf('Time taken: %5d days %5d hours %5d minutes %5d seconds\n\n', elapsed_time(3), elapsed_time(4), elapsed_time(5), elapsed_time(6));

fprintf('Average accuracy over %d times: mean+std %5.2f+%3.2f\n', iter_num, mean(accuracies), std(accuracies));  

total_end_time = round(clock);
fprintf('Total time of the classification program is:\n');
disp(total_start_time);
disp(total_end_time);