function [idxs, centers] = clusterNormalAndHOG(patchData, HOGFeatures, params)

    globals;
    normalSrc = CONFIG.normals;

    imageSize = [480 640];
    patchTargetSize = [10 10];
    normalDim = patchTargetSize(1)*patchTargetSize(2)*3;
    HOGDim = size(HOGFeatures,2);

    %get normal features
    nPatches = size(HOGFeatures,1);
    patchNormalValid = zeros(nPatches, normalDim);
    normals = zeros(nPatches, normalDim);
    bboxOnEdge = zeros(nPatches, 1);

    filenames = {};
    bboxes = {};
    indices = {};
    
    for i=1:numel(patchData)
        pos = patchData(i);
        imPath = pos.im;
        [~,imName,ext] = fileparts(imPath);
        fileLocation = -1;
        %scan for the filename
        for j=1:numel(filenames)
            if(strcmp(filenames{j},imName))
                fileLocation = j;
                break;
            end
        end
        if(fileLocation == -1)
            fileLocation = numel(filenames)+1;
            filenames{fileLocation} = imName;
            bboxes{fileLocation} = [];
            indices{fileLocation} = [];
        end

        bboxes{fileLocation} = [bboxes{fileLocation}; [pos.x1, pos.y1, pos.x2, pos.y2]];
        indices{fileLocation} = [indices{fileLocation}; i]; 
    end


    for fi=1:numel(filenames)
        fprintf('Handling file %d/%d\n',fi,numel(filenames));
        imName = filenames{fi};
        %load the data

        %nx, ny, nz, depthValid
        load([normalSrc strrep(imName, 'rgb', 'nm') '.mat']);
        %clip any issues:w

        nx = max(min(nx,1),-1); ny = max(min(ny,1),-1); nz = max(min(nz,1),-1);


        for ii=1:numel(indices{fi})
            ind = indices{fi}(ii);
            bbox = bboxes{fi}(ii,:);
            minX = bbox(1); minY = bbox(2); maxX = bbox(3); maxY = bbox(4);

            %get the distances to the border
            xDistance = min(minX,imageSize(2)-maxX);
            yDistance = min(minY,imageSize(1)-maxY);
            closestPatch = min(xDistance, yDistance);


%            pValidImage = depthImage(minY:maxY,minX:maxX) > 0;
            pValidImage = depthValid(minY:maxY,minX:maxX) > 0;
            pnx = nx(minY:maxY,minX:maxX);
            pny = ny(minY:maxY,minX:maxX);
            pnz = nz(minY:maxY,minX:maxX);
        
            %resize to canonical size
            pValidImage = imresize_old(pValidImage, patchTargetSize);
            pValidImage = pValidImage >= 1;
            pnx = imresize_old(pnx, patchTargetSize);
            pny = imresize_old(pny, patchTargetSize);
            pnz = imresize_old(pnz, patchTargetSize);

            %dump normals
            patchNormalValid(ind,:) = [repmat(pValidImage(:)',1,3)]; 
            normals(ind,:) = [pnx(:)' pny(:)' pnz(:)'];
            if(closestPatch < 10)
                bboxOnEdge(ind) = 1; 
            end
        end
    end

    K = 1000; minIsect = 5; maxClusterMembers = 5;

    %reduced set 
    valid = (mean(patchNormalValid,2) > 0.5) .* (~bboxOnEdge);
    reduced = find(valid);
    normalsRed = normals(reduced,:);
    HOGFeaturesRed = HOGFeatures(reduced,:);

    fprintf('Computing neighbors in normal space\n');
    [~,INormalRed] = pdist2(normalsRed, normalsRed, 'cosine', 'Smallest',K);

    fprintf('Computing neighbors in HOG space\n');
    [~,IHOGRed] = pdist2(HOGFeaturesRed, HOGFeaturesRed, 'euclidean', 'Smallest',K);

    %upgrade to the full set later
    numValidPatches = size(normalsRed,1);

    numIsect = computeNearbyDualIsect(IHOGRed(2:K,:),INormalRed(2:K,:));
    [~,clusterIndices] = sort(numIsect,'descend');
    numValid = sum(numIsect >= minIsect);

    clusterAssign = zeros(1, numValidPatches);
    %the centers are at most numValid in count
    centers = zeros(numValid, HOGDim);
   
    numClusters = 0;
    for ii=1:numValid
        i = clusterIndices(ii);
        %if we've already assigned this
        if(clusterAssign(i) ~= 0)
            continue;
        end 
        numClusters = numClusters + 1;
        %assignees (the intersected HOG and normal space)
        [toUse,hogRank,normalRank] = intersect(IHOGRed(1:K,i),INormalRed(1:K,i));
        mergedRank = hogRank + normalRank;
        %check which ones are valid (have not been assigned yet)
        %and assign them
        patchValid = (clusterAssign(toUse) == 0);
        toUse = toUse(patchValid);

        mergedRank = mergedRank(patchValid);
        [~,useOrder] = sort(mergedRank);
        %sort them by preference
        toUse = toUse(useOrder);
        if(numel(toUse) == 0)
            continue;
        end
        %select top N
        toUse = toUse(1:min(maxClusterMembers,numel(toUse)));

        clusterAssign(toUse) = numClusters; 
        %compute the center
        centers(numClusters,:) = mean(HOGFeatures(toUse,:));
    end
    %
    centers = centers(1:numClusters,:);
    idxs = zeros(1, nPatches);
    idxs(reduced) = clusterAssign;

end
