%% PCA via KLT on downsampled Yale face database
%  ECE 792-41 Statistical Foundations for Signal Processing and Machine Learning
%  Prof. Chau-Wai Wong, ECE, NC State University, Sept. 2020

%% (a) Load image data
preview_img_flag = 0;
dataset_path = 'yalefaces/';
filename_filter = 'subject*';
[img_buffer, num_imgs, img_dim] = LoadImgData(dataset_path, filename_filter, preview_img_flag);

%% (b) PCA via KLT
data = cat(2, img_buffer{:});  % create a matrix in which each column corresponds to an image.

[V, Lambda_mat] = PcaViaKlt(data);

lambda_vec = diag(Lambda_mat);  % take out the diagonal elements of a matrix and organize them into a vector
[lambda_vec_sorted, index_sorted] = sort(lambda_vec, 'descend');
V_sorted = V(:, index_sorted);  % rearrange the eigenvectors (columns) according to decreasing eigenvalues

figure(1); plot(lambda_vec_sorted(1:25), '-o'); grid on;
axis([1 25 0 max(lambda_vec)]);
xlabel('Index of sorted $\{\lambda_i$\}', 'interpreter', 'latex'); 
ylabel('$\lambda_i$', 'interpreter', 'latex');

%% (c) Eigenvector/eigenface visualization
num_eigenvector_to_visualize = 8;
figure(2);
for i = 1 : num_eigenvector_to_visualize
  eigenface = reshape(V_sorted(:, i), img_dim);  % convert vectorized image into 2D form
  imshow(imresize(eigenface, [nan 200], 'nearest'), []);  % display a larger version
  title_str = sprintf('\\lambda_{%d} = %.2f', i, lambda_vec_sorted(i));
  title(title_str);
  pause(0.5);
end

%% (d) PCA for data visualization
c = {'centerlight', 'leftlight', 'normal', 'rightlight'};  % categories to be visualized

figure(3);
for k = 1 : length(c)
  filename_filter = ['*.' c{k}];
  img_buffer = LoadImgData(dataset_path, filename_filter, 0);  % load image data by category without preview
  data = cat(2, img_buffer{:});
  
  X_2pc = V_sorted(:, 1:2)' * data;  % projecting images onto the first two principal components
  
  plot(X_2pc(1, :), X_2pc(2, :), '.', 'MarkerSize', 30); hold on;
  xlabel('PC1'); ylabel('PC2');
  drawnow;
end
hold off;
legend(c);
grid on; grid minor;

