function canonicalForms = estimateCanonical(clusterMetadata)
    globals;
    normalSource = CONFIG.normals;
    toProcess = clusterMetadata.selectedClusters;
    fprintf('Estimating canonical forms\n');
    canonicalForms = {};
    for ii=1:numel(toProcess)
        fprintf('%d / %d\n', ii, numel(toProcess));
        i = toProcess(ii);
        memberIds = find(clusterMetadata.assignedClust == i);
        clusterPatches = {};
        for mii = 1:numel(memberIds)
            memberId = memberIds(mii);
            patchData = clusterMetadata.positivePatches(memberIds(mii));
            imageSource = patchData.im;
            [~,imageFilename,~] = fileparts(imageSource);
            normalFilename = [strrep(imageFilename,'rgb','nm') '.mat']; 
            normalData = load([normalSource '/' normalFilename]);
            x1 = patchData.x1; x2 = patchData.x2;
            y1 = patchData.y1; y2 = patchData.y2;
            p.patchNx = normalData.nx(y1:y2,x1:x2);
            p.patchNy = normalData.ny(y1:y2,x1:x2);
            p.patchNz = normalData.nz(y1:y2,x1:x2);
            p.patchValid = normalData.depthValid(y1:y2,x1:x2);
            clusterPatches{mii} = p;
        end
        canonicalized = canonicalizePatchData(clusterPatches);
        canonicalForm = computePatchMedian(canonicalized);
        canonicalForms{ii} = cat(3,canonicalForm.patchNx,canonicalForm.patchNy,canonicalForm.patchNz);
    end 
end
