function scores = computeScores(clusterSource)
    metadataTarget = [clusterSource '/clusterScores/'];

    %load the patch data and metadata
    patchData = dir([clusterSource '/patchdata*mat']);
    patches = {};
    bboxes = {};
    imageSizes = {};
    for i=1:numel(patchData)
        patchNumber = str2num(strrep(strrep(patchData(i).name, 'patchdata_', ''),'.mat',''));
        patches{i} = load([clusterSource '/' patchData(i).name]);
        bboxes{i} = dlmread(sprintf('%s/bbox_%d.txt',clusterSource,patchNumber)); 
        imageSizes{i} = dlmread(sprintf('%s/imagedim_%d.txt',clusterSource,patchNumber));
    end 

    %canonicalize the patch data and compute average patches 
    canonicalData = canonicalizePatchData(patches);
    medianPatches = computePatchMedian(canonicalData);

    %get a cell array of the patches normals
    getNormalField = @(x)({x.patchNx, x.patchNy, x.patchNz});
    getDepthField = @(x)({x.patchDepth});

    %compute scores for patch data
    scores.normalMeanD = computePatchDistance(canonicalData, medianPatches, getNormalField, @(x)(nanmean(x,3)));
    scores.normalMaxD = computePatchDistance(canonicalData, medianPatches, getNormalField, @(x)(nanmax(x,[],3)));
    scores.depthMeanD = computePatchDistance(canonicalData, medianPatches, getDepthField, @(x)(nanmean(x,3)));
    scores.depthMaxD = computePatchDistance(canonicalData, medianPatches, getDepthField, @(x)(nanmax(x,[],3)));

    scores.depthAvailability = computeDepthAvailability(canonicalData);
   
    %compute minimum border distances 
    minBorderDistances = zeros(1,numel(patchData));
    for i=1:numel(patchData)
        minBorderDistances(i) = computeMinBorderDistance(bboxes{i}, imageSizes{i});
    end
    scores.minBorderDistances = minBorderDistances;


    %write the scores out
    if(~exist(metadataTarget))
        mkdir(metadataTarget);
    end
    dlmwrite([metadataTarget '/normalMeanD.txt'], scores.normalMeanD);
    dlmwrite([metadataTarget '/normalMaxD.txt'], scores.normalMaxD);
    dlmwrite([metadataTarget '/depthMeanD.txt'], scores.depthMeanD);
    dlmwrite([metadataTarget '/depthMaxD.txt'], scores.depthMaxD);
    dlmwrite([metadataTarget '/depthAvailability.txt'], scores.depthAvailability);
    dlmwrite([metadataTarget '/minBorderDistances.txt'], scores.minBorderDistances);

end

function score = computePatchDistance(patches, average, fieldGetter, pool)
    %Compute the patch distance to the average patch
    %
    %fieldGetter takes an object and returns cell array of matrices
    %pool takes a [WxHxN] collection of patches and pools the responses over the
    %   patch
    patchFields = fieldGetter(patches);
    averageFields = fieldGetter(average);

    scoreConcat = [];
    for i=1:numel(patchFields)
        distances = abs(bsxfun(@minus,patchFields{i}, averageFields{i}));
        pooled = pool(distances);
        scoreConcat = [scoreConcat; pooled(:)];
    end
    score = nanmean(scoreConcat);
    if(isnan(score))
        score = 1e10;
    end
end

function availability = computeDepthAvailability(patches)
    depthValid = patches.patchDepth > 1e-3;
    availability = mean(depthValid(:)); 
end

function minDistance = computeMinBorderDistance(bbox,imageDim)
    h = imageDim(1); w = imageDim(2);
    %compute the minimum distance to the image border
    minDistance = min([bbox(1) / w, bbox(2) / h, 1 - bbox(3)/w, 1 - bbox(4)/h]); 
end


