%% Results
% I used HOG and LBP features > dimenstions of feature-vector: 2000x1869
% Best result: 53.8% at 2000 training and 2000 testing images
% Second best: 49.8% at 1000 training and 1000 testing images

%% Inicialization
% Adding the path of functions and loading data files
addpath('./libsvm-3.21/windows');                % Using SVM from libsvm
addpath(genpath('./vlfeat-0.9.20/toolbox/mex')); % add all subfolders in the given folder
addpath('./cifar10');                            % Get data from cifar database
tr_meta  = load('./cifar10/batches.meta.mat');
tr_set   = load('./cifar10/data_batch_1.mat');
test_set = load('./cifar10/test_batch.mat');

tr_selection   = 10; % Use every 5th image for training
test_selection = 10; % Use every 5th image for testing

% Prepare training set
tr_set_data   = double(rgb2gray( reshape( tr_set.data(1 : tr_selection : end, :), [10000/tr_selection, 1024, 3] ) ));
tr_set_labels = double(tr_set.labels(1 : tr_selection : end, :));

% Prepare testing set
test_set_data   = double(rgb2gray( reshape( test_set.data(1 : test_selection : end, :), [10000/test_selection, 1024, 3] ) ));
test_set_labels = double(test_set.labels(1 : test_selection : end, :));

%% A basic svm model can be created and tested for comparsion
% perm_vector = randperm(32*32, 650); % to decrease the size of the training and testing set
% % Trains an SVM model on the basis of images (pixel intensities)
% svm_options = ['-s 0 -t 0 -q -h 1 -b 1 -c ', num2str( C ) , ' -g ', num2str( g ) ];
% final_model = svmtrain(tr_set_labels, tr_set_data(:, perm_vector), svm_options);
% % Tests the previous SVM model on the test images
% [ ~ , acc, ~ ] = svmpredict(test_set_labels, test_set_data(:, perm_vector), final_model, '-b 1 -q');
% fprintf('The accuracy of the basic svm model on the test set is %2.0f%%\n', acc(1));

%% Feature extraction
% Extracts the HOG- and LBP-features from the train images
tr_features = zeros(size(tr_set_data, 1), (1+4+16)*(31+58));
parfor i = 1:size(tr_set_data, 1)
    img = reshape(tr_set_data(i,:),32,32); % get image
    
    % Extract HOG-features by different window sizes
    hog_window32 = vl_hog(im2single(img),32);
    hog_window16 = vl_hog(im2single(img),16);
    hog_window8 = vl_hog(im2single(img),8);
    
    % Extract LBP-features by different window sizes
    lbp_window32 = vl_lbp(im2single(img),32);
    lbp_window16 = vl_lbp(im2single(img),16);
    lbp_window8 = vl_lbp(im2single(img),8);
    
    % Combine HOG- and LBP-features to a single feature-vector
    tr_features(i,:) = vertcat(hog_window32(:), hog_window16(:), hog_window8(:), ...
                          lbp_window32(:), lbp_window16(:), lbp_window8(:));
end

% Extracts the HOG- and LBP-features from the test images
test_features = zeros(size(test_set_data, 1), (1+4+16)*(31+58));
parfor i = 1:size(test_set_data, 1)
    img = reshape(test_set_data(i,:),32,32); % get image
    
    % Extract HOG-features by different window sizes
    hog_window32 = vl_hog(im2single(img),32);
    hog_window16 = vl_hog(im2single(img),16);
    hog_window8  = vl_hog(im2single(img),8);
    
    % Extract LBP-features by different window sizes
    lbp_window32 = vl_lbp(im2single(img),32);
    lbp_window16 = vl_lbp(im2single(img),16);
    lbp_window8  = vl_lbp(im2single(img),8);
    
    % Combine HOG- and LBP-features to a single feature-vector
    test_features(i,:)  = vertcat(hog_window32(:), hog_window16(:), hog_window8(:), ...
                           lbp_window32(:), lbp_window16(:), lbp_window8(:));
end

% Find optimal C and g values
[ C, g ] = gridsearch(tr_set_labels, tr_features);

% trains another SVM model on the basis of the prev. extracted HOG- and LBP-features
svm_options = ['-s 0 -t 0 -q -h 1 -b 1 -c ', num2str( C ) , ' -g ', num2str( g ) ];
svm_model_hog = svmtrain( tr_set_labels, tr_features, svm_options );
[ ~ , acc, ~ ] = svmpredict(test_set_labels, test_features, svm_model_hog, '-b 1 -q');
fprintf('The accuracy of the svm model of hog and lbp features on the test set is %2.0f%%\n', acc(1));

