function [ s1Dictionary ] = learn_s1_dictionary(imgDatabase,param)
% This function is to train low-level dictionary using sparse coding
% Input:   imgDatabase  -- the database of normalized images
%          param        -- see the default setting below
% Output:  s1Dictionary -- low-level dictionary, each column represents a
%                          basis in the dictionary
% Written by Jimei Yang
% Oct. 28, 2009
if ~isfield(param,'nSmpForS1Dict')
    param.nSmpForS1Dict = 200000;
end
if ~isfield(param,'patchSize')
    param.patchSize = 16;
end
fprintf('-- sample features from the image layer...\n');
num_img = length(imgDatabase.label); % num of images
num_per_img = round(param.nSmpForS1Dict/num_img);
num_h = round(num_per_img^.5);
num_w = round(num_per_img/num_h);
num_smp = num_h*num_w*num_img;


X = zeros(param.patchSize^2, num_smp);
cnt = 1;
for ii = 1:num_img
    fpath = imgDatabase.path{ii};
    load(fpath);
    [im_h,im_w] = size(img);
    % make grid sampling appearance patches
    remX = mod(im_w-param.patchSize,param.gridSpacing);
    offsetX = floor(remX/2)+1;
    remY = mod(im_h-param.patchSize,param.gridSpacing);
    offsetY = floor(remY/2)+1;

    xBin = offsetX:param.gridSpacing:im_w-param.patchSize+1;
    yBin = offsetY:param.gridSpacing:im_h-param.patchSize+1;
    x_num = length(xBin);
    y_num = length(yBin);
    
    rndX = randperm(x_num);
    rndX = rndX(1:num_w);
    rndY = randperm(y_num);
    rndY = rndY(1:num_h);
    for jj = rndX
        for kk = rndY
            patch = img(jj:jj+param.patchSize-1,kk:kk+param.patchSize-1);
            pNorm = norm(patch(:));
            if pNorm > 0
                patch = patch(:)/pNorm;
            else
                patch = patch(:);
            end
            X(:, cnt) = patch;
            cnt = cnt+1;
        end
    end
end
X(:,sum(X.^2)==0) = [];
save X X;

% set parameters for dictionary learning
if ~isfield(param,'nBasesS1')
    param.nBasesS1 = 1024;
end
if ~isfield(param,'beta')
    param.beta = 1e-3; % a small regularization for stablizing sparse coding
end
if ~isfield(param,'gama')
    param.gama = 0.15;
end
if ~isfield(param,'maxIter')
    param.maxIter = 50;
end
fprintf('-- train sparse coding...');
[s1Dictionary] = reg_sparse_coding(X, param.nBasesS1, eye(param.nBasesS1), param.beta, param.gamma, param.maxIter);
