GenerateHoughClusters.m

function GenerateHoughClusters(list_of_matches)
% This function takes list of matches as input and computes outliers /
% moving objects / background; exports to a file.
 
	% First, some constants
	% Label for moving objects
	MOVING_OBJECT = 1;
	% Label for outliers
	OUTLIER = -1;
    % Label for background
    BACKGROUND = 0;
 
	% A point must be at most this far away to be part of a cluster
	NEIGHBORHOOD_THRESHOLD = 15;
 
    % Determines whether to graph outliers or not (red)
    SHOW_OUTLIERS = 0;
 
	% It is possible that the plane is tracking the moving object.
	% In this case the tiepoints will be so close to each other, 
	% the angles won't make any sense. We can detect this by looking
	% at the line lengths and if they are too smal, we set the angle to 0
	LINE_LENGTH_THRESHOLD = 5; %pixels
 
    % columns location of image locations in matches
    locs = [2,3,7,8];
 
    % ****************************************************************
    % This is the key data structure containing the whole scene
    % The column format is the following:
    % x_ref y_ref x_tar y_tar angle distance label
    scene = zeros(0,8);
    prevousScene = scene;
    GlobalScene = scene;
    % ****************************************************************
 
    % Structure of scene
    refXIndex = 1;
    refYIndex = 2;
    tarXIndex = 3;
    tarYIndex = 4;
    angleIndex    = 5;
    distanceIndex = 6;
    labelIndex    = 7;
    timeIndex	  = 8;
 
    % Create the figure and label axes
    %HoughFigure = figure('Position', [100 100 1024 768],'PaperPosition',[0 0 30 20]);
    %xlabel('Line angle');
    %ylabel('Line length');
    %zlabel('Time');
    %title('Hough space');
    %hold on;
 
    % Open the matches list
    hMap = fopen(list_of_matches, 'r');
    fprintf('Reading matches map file\n');
    time = 0;
    label = 1;
    changeLabel = 0;
 
    % Read the list of match files
    while(~feof(hMap))
        fprintf('File # = %d\n', time);
 
        % Save the scene so that we can match the next frame with the
        % clusters from the current frame
        previousScene = scene;
 
        scene = zeros(0,8);
        matchFile = fgetl(hMap);
        if (exist(matchFile)==0)
            fprintf('File # %d does not exist\n', time);
            time = time +1;pre
            continue;
        end
        % Read in matches
        matches = load(matchFile);
        matches = RemoveDuplicates(matches);
        numMatches= size(matches, 1);
 
 
        % Calculate angles and distances, label all points as "background" (0)
        for j = 1:numMatches
            ptRef = [matches(j, locs(1)), matches(j, locs(2))];
            ptTar = [matches(j, locs(3)), matches(j, locs(4))];
            distance = Distance(ptRef, ptTar);
            if (distance < LINE_LENGTH_THRESHOLD)
                angle = 0;
            else angle = Angle(ptRef, ptTar);
            end
 
            %if (time == 0)
                % label everything with "0" for now - as background
            %    label = label + 1;
            %    changeLabel = label;
            %else
 
            %    changeLabel = FindLabel(ptRef, previousScene);
            %    if (changeLabel == -1)
            %        label = label + 1;
            %        changeLabel = label;
            %    end
            %end
            %scene = vertcat(scene, [ptRef, ptTar, angle, distance, changeLabel, time]);
            scene = vertcat(scene, [ptRef, ptTar, angle, distance, BACKGROUND, time]);
 
        end % calculating angles and distances
 
 
 
        % Calculate median distance and slope (hypothetical center of background cluster)
        %scene = sortrows(scene, angleIndex);
        %medianAngle = median(scene(:, angleIndex));
        %scene = sortrows(scene, distanceIndex);
        %medianDistance = median(scene(:, distanceIndex));
 
        % Try to find all Hough clusters, starting with the first point in
        % the list
        % Each point could be its own cluster
 
        possibleCluster = 1;
 
        % Number of points left in the scene (will change)
        numMatchesLeft = numMatches;
        while (possibleCluster <= numMatchesLeft)
 
            % For now, the first point in the cluster is its own neighbor
            neighbors = scene(possibleCluster, :);
 
            % The first point in the cluster is the seed of the cluster
            seed = scene(possibleCluster, angleIndex:distanceIndex);
 
            % Remove the seed point from the scene
            scene(possibleCluster,:) = [];
 
 
 
            %###
            % Find the neighbors of the seed, recursively - find N neighbors
            % near the seed within the circle defined by NEIGBORHOOD_THRESHOLD,
            % then for each of those neighbors find its neighbors within their
            % individual circles
            %
            % As the neighbors are found, they are removed from scene
            [neighbors scene] = FindNeighbors(neighbors, scene, seed, NEIGHBORHOOD_THRESHOLD);
 
            % What is the total number of matches now? (could be numMatches-1)
            numMatchesLeft = size(scene,1);
 
            % Store all the neighbors in a separate data structure - now a full
            % cluster.
            clusterContainer = neighbors;
 
            % Check how many neighbors were found
            clusterCount = size(clusterContainer, 1);
 
 
 
            % #################################################################
            % Now we have a cluster of points to plot - here we determine
            % whether it's the background, a moving object, or an outlier
            % #################################################################
 
            % If there are more than 2 points but less than 20 percent of
            % total, it's a moving object, color it BLUE
            if (clusterCount > 2 && clusterCount < round(0.2*numMatches))
                clusterContainer(:, labelIndex) = MOVING_OBJECT * ones(clusterCount, 1);
                %set(0,'CurrentFigure', HoughFigure);
                %for i = 1:clusterCount
                    %color = ones(1,3) * clusterContainer(i, labelIndex);
                    %plot3(clusterContainer(i, angleIndex), clusterContainer(i, distanceIndex), ones(1,1)*time, 'Color', color, 'Marker', '.', 'MarkerSize', 5, 'LineStyle', 'none');
                %end
                 %plot3(clusterContainer(:, angleIndex), clusterContainer(:, distanceIndex), ones(clusterCount,1)*time, 'Color', color, 'Marker', '.', 'MarkerSize', 5, 'LineStyle', 'none');
            else
                % If there are less than 3 percent, these are
                % outliers/crossovers, they are RED
                if (clusterCount < round(0.03*numMatches))
 
                    % But FIRST, check the previous frame, if it exists,
                    % whether there are any neighbors around these points
                    % in the previous frame
 
                    if (time ~= 0)
 
                        % clusterContainer contains the 'outliers'
                        % previousScene is the previous frame
                        % for each 'outlier' point in clusterContainer we
                        % need to look for possible neighbors in the
                        % previous frame - if at least one exists, then the
                        % neighbor in the previous frame and the current
                        % 'outlier' are not outliers but moving objects
                        % instead
 
                        numOutliers = size(clusterContainer, 1);
                        for outlier = 1:numOutliers
                            outlierSeed = clusterContainer(outlier, :);
                            outlierNeighbors = zeros(0,8);
 
                            % since the network is modified (neighbors are
                            % removed), we need to save it and use a fresh
                            % copy for each outlier - it's possible two
                            % outliers may share the same neighbor in the
                            % previous frame
                            outlierNetwork = previousScene;
 
                            % find neighbors in the previous frame
                            [outlierNeighbors outlierNetwork] = FindNeighbors(outlierNeighbors, outlierNetwork, outlierSeed, NEIGHBORHOOD_THRESHOLD);
 
                            % how many neighbors for the outlier were found?
                            numOutlierNeighborsInPrevFrame = size(outlierNeighbors,1);
 
                            if (numOutlierNeighborsInPrevFrame > 0)
                                % If neighbors were found, current
                                % 'outlier' is not an outlier
                                clusterContainer(outlier, labelIndex) = MOVING_OBJECT;% * ones(clusterCount, 1);
 
                                % The neighbors found in the previous scene are not outliers either
 
                                for numPointsToEdit = 1:numOutlierNeighborsInPrevFrame
 
                                    % Remove previous frame from global scene
                                    % GlobalScene(find(GlobalScene(:, timeIndex) = time),:) = [];
                                    GlobalScene(:, timeIndex == time) = [];
                                    % Change found neighbors to MOVING_OBJECT
                                    outlierNeighbors(:, labelIndex) = MOVING_OBJECT * ones(numOutlierNeighborsInPrevFrame, 1);
                                    % Put neighbors and previous frame back into global scene
                                    GlobalScene = vertcat(GlobalScene, outlierNeighbors);
                                    GlobalScene = vertcat(GlobalScene, outlierNetwork);
 
                                    clusterContainer(outlier, labelIndex) = OUTLIER;% * ones(clusterCount, 1);
                                end % for
 
                            else
                                clusterContainer(outlier, labelIndex) = OUTLIER;% * ones(clusterCount, 1);
                            end
 
                        end %for outlier
 
 
                        %color = 'red';   
                        %if (SHOW_OUTLIERS)
                            %set(0,'CurrentFigure', HoughFigure);
                            %plot3(clusterContainer(:, angleIndex), clusterContainer(:, distanceIndex), ones(clusterCount,1)*time, 'Color', color, 'Marker', '.', 'MarkerSize', 5, 'LineStyle', 'none');
                        %end
                    %else % If there are more than 20% of the points in the cluster,
                         % then the cluster is background, the points are GREEN
                        %color = 'green';
                        %set(0,'CurrentFigure', HoughFigure);
                        %plot3(clusterContainer(:, angleIndex), clusterContainer(:, distanceIndex), ones(clusterCount,1)*time, 'Color', color, 'Marker', '.', 'MarkerSize', 5, 'LineStyle', 'none');
                    end % if time != 0
 
                end % if (outlier)
            end % else 
            GlobalScene = vertcat(GlobalScene, clusterContainer);
        end % while possible cluster >=numMatches
        time = time + 1;
 
 
        %pause;
    end    % end reading in matches files
 
    save GlobalScene.mat GlobalScene
 
    % These functions are defined within showMatches, not outside
    %---------------------------------------------------------------------------------------------
 
    % Calculates angle between two points
    function angle = Angle(ptA, ptB)
        %if (ptA(2)-ptB(2) == 0)
        %    angle = -1;
        %    return
        %end
        angle = atan2((ptA(2)-ptB(2)),(ptA(1)-ptB(1)));
        angle = 180/pi * angle;
    end
 
 
    %---------------------------------------------------------------------------------------------
 
 
    % Calculates distance between two points
    % ptB could be a vector, then distance is a vector of distances
    function distance = Distance(ptA, ptB)
 
        % if pointB is a vector
        [rows cols] = size(ptB);
        if (rows > 1)
            for i = 1:rows
                distance(i) = sqrt(sum((ptA - ptB(i,:)).^2));
            end
 
        else
            distance = sqrt(sum((ptA - ptB).^2));
        end
    end
 
 
    %---------------------------------------------------------------------------------------------
 
 
    % Export current figure to file
	function ExportFigure(matchesFigure, HoughFigure, matchPath)
	  % extract filename
	  [pathstr, name, ext, versn] = fileparts(matchPath);
 
	  % construct new filename with new extension
	  matchesimg=fullfile('matches_', name, '.jpg');
	  % remove backslash from name - matlab 'feature'
	  matchesimg(matchesimg=='\') = [];
	  matchesimg(matchesimg=='/') = [];
 
	  % construct new filename with new extension
	  houghimg=fullfile('hough_', name, '.jpg');
	  % remove backslash from name - matlab 'feature'
	  houghimg(houghimg=='\') = [];
	  houghimg(houghimg=='/') = [];
 
	  % export to jpeg
	  set(0,'CurrentFigure', matchesFigure);
	  print('-djpeg', '-r300', matchesimg);
	  set(o,'CurrentFigure', HoughFigure);
	  print('-djpeg', '-r300', houghimg);
 
	  %print('-dtiff', 'SIFT.tif')
    end
 
    %---------------------------------------------------------------------------------------------
 
 
	%-----------------------------------------------------------------------------------------------------------------------------------
 
	% The recursive function which, given a seed point, recursively finds all neighbors and their neighbors and so on
	% in the neighborhood of the original seed within a threshold
    % Each of the neighbors found around the seed becomes a new seed for
    % the recursion
 
	% neighbors: as input, 1x8 vector containing the original seed point so that it doesn't get lost
 
	% network: points we're looking at
	% seed: where are we starting to look
	% distance: threshold around the seed to find first neighbors
 
	% returns neighbors and modified network (not containing the neighbors)
	function [neighbors network] = FindNeighbors(neighbors, network, seed, distance)
		if (size(network, 1) == 0)
		%	neighbors = [];
			return
        end
 
        % Compute distances from the seed to each point in the network
        distances = abs(Distance(seed, network(:, angleIndex:distanceIndex)));
 
        % Select the indices of the network points which are within the
        % circle
		neighborIndices = find(distances < distance);
 
		% Termination step. Function terminates when there are no neighbors.
        numNeighbors = size(neighborIndices, 2);
		if (numNeighbors == 0)
			%neighbors = [];
			return
		end
 
		% Add newly found points to the neighbors matrix
		neighbors = vertcat(neighbors, network(neighborIndices,:));
 
		% Remove newly found points from the network 
		network(neighborIndices,:) = [];
 
 
		% Recursive step: for each of the newly found neighbors, find neighbors within the threshold
		% Function terminates when there are no neighbors
 
		%recursion = 1;
		%while( recursion < numNeighbors )
		for recursion = 1:numNeighbors
			newNeighbors = [];
			newSeed = neighbors(recursion, angleIndex:distanceIndex);
			%newNeighbors = neighbors(recursion, :);
			[newNeighbors network]= FindNeighbors(newNeighbors, network, newSeed, distance);
			if (size(newNeighbors,2) > 0)
				neighbors = vertcat(neighbors, newNeighbors);
			end
		end
 
	end
 
 
 
 
	%-----------------------------------------------------------------------------------------------------------------------------------
	% Removes duplicate SIFT matches
	function frame = RemoveDuplicates(frame)
		[numPts cols] = size(frame);
		i = 1;
        j = 1;
        while (i < numPts )
            j = i+1;
            while (j < numPts)
                if ((frame(i,1) == frame(j,1) && frame(i,2) == frame(j,2)) || (frame(i,3) == frame(j,3) && frame(i,4) == frame(j,4)))
                    frame(i,:) = [];
                    numPts = numPts - 1;
                end
                j = j + 1;
            end
            i = i + 1;
        end
        return
    end
 
    %-----------------------------------------------------------------------------------------------------------------------------------
 
    function label = FindLabel(ptRef, previousScene)
 
        distances = Distance(ptRef, previousScene(:, tarXIndex:tarYIndex));
        [rows cols] = size(distances);
        distances = reshape(distances, [cols rows]);
        distances = horzcat(distances, previousScene(:, labelIndex));
        distances = sortrows(distances, 1);
        if (distances(1,1) < NEIGHBORHOOD_THRESHOLD)
            label = distances(1, 2);
        else
            label = -1;
        end
 
 
    end
    %-----------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
 
 
end    % end GenerateHoughClusters function