Skip to content

Commit

Permalink
Added an initial set of files
Browse files Browse the repository at this point in the history
Initial code for the repository
  • Loading branch information
semihyagcioglu committed Jun 29, 2015
1 parent 94699cd commit dfeef61
Show file tree
Hide file tree
Showing 43 changed files with 4,194 additions and 0 deletions.
34 changes: 34 additions & 0 deletions ComputeMatchScore.m
@@ -0,0 +1,34 @@
function [score] = ComputeMatchScore(im1, im2, method, Settings)

% Given two images, return a score based on their match cost. The lower, the better.
%
% Inputs: im1 - Input image 1
% im2 - Input image 2
% method - Match method (DSP or SIFT)
% Settings - Application wide settings used to store algorithm parameters, paths etc.
%
% Outputs: score - Match cost, lower score means two images match better.

score = 0;

if(strcmp(method, 'DSP'))
% pca_basis: pca basis for dimensionality reduction of sift
%load('dsp/lmo_pca_basis.mat', 'pca_basis');
pca_basis = []; % if you want to use the sift of original dimension
sift_size = 4; % sift patch size 16 x 16 pixels (i.e., patch_size = 4*sift_size)
% Extract SIFT
[sift1, ~] = ExtractSIFT(im1, pca_basis, sift_size);
[sift2, ~] = ExtractSIFT(im2, pca_basis, sift_size);
[~, ~, match_cost] = DSPMatch(sift1, sift2);
score = mean2(match_cost); % Compute the score based on the match_cost of DSP matrix.

else if(strcmp(method, 'SIFT'))
im1 = single(rgb2gray(im1)); % Convert to single, since it is recommended
im2 = single(rgb2gray(im2));
[F1 D1] = vl_sift(im1); % Extract sift features and descriptors
[F2 D2] = vl_sift(im2); % Extract sift features and descriptors
L2Ratio = Settings.L2Ratio4SIFT; % Euclidean distance ratio of NN2/NN1, used to filter matches
[matches score] = vl_ubcmatch(D1, D2, L2Ratio);
score = mean2(score);
end
end
160 changes: 160 additions & 0 deletions DemoApp.m
@@ -0,0 +1,160 @@
function [averageEstimationError] = DemoApp(mode, parameters)

% Geolocalize given query scene(s) using a reference dataset.
%
% Inputs: mode - only test mode for now
% parameters - simply a struct with the same fields as settings. You can set any field as you wish.
%
% Outputs: averageEstimationError - average estimation error for given scene(s)

addpath(genpath('lib')); % Environment variables.
Settings = LoadSettings('data/settings.ini'); % Load default settings.

if(strcmp(mode,'test') && exist('parameters','var')) % In test mode, if provided override default settings
parameterFields = fieldnames(parameters);
for loopIndex = 1:numel(parameterFields)
if(isfield(Settings,parameterFields{loopIndex})) % If there is a same field in Settings
Settings.(parameterFields{loopIndex}) = parameters.(parameterFields{loopIndex});
end
end
end

Settings.InitialResultPath = Settings.ResultPath; % Used to reset to initial folder
Results = struct('QueryImageName', [], 'QueryImageLatitude', 0, 'QueryImageLongitude', 0, 'EstimatedLatitude', 0, 'EstimatedLongitude', 0, 'EstimationError', 0, 'ComputationTime', 0, 'Success', 0, 'TimesBetterThanChance', 0);
JointResults = struct('QueryImageName', [], 'EstimationError', 0, 'ComputationTime', 0, 'Success', 0, 'ByChanceDistanceError', 0, 'TimesBetterThanChance', 0);
baseFolder = [datestr(now,30) '-' Settings.ExperimentName] ;
mkdir(Settings.ResultPath, baseFolder); % Create a base directory to save the results for the input.
disp('Starting Geolocalization...');
AllItems = LoadPreRequisites(Settings);

if(Settings.SizeCap ~= 0 && length(AllItems) > Settings.SizeCap)
r = randi(length(AllItems), Settings.SizeCap, 1); % Get random integers
AllItems = AllItems(r); % Reduce dataset size by selecting random items from dataset, for size effect in the paper.
clear r;
end

if(strcmp(mode,'test')) % Test mode
inputImageList = dir([Settings.QueryDataPath '*.jpg']); % Get query image list
if isempty(inputImageList)
error('Cannot find the query images.');
end
[~,order] = sort_nat({inputImageList.name}); % Sort images in asc order.
inputImageList = inputImageList(order);
imageCount = length(inputImageList);
end

if(Settings.SequenceCap ~= 0 && imageCount > Settings.SequenceCap)
imageCount = Settings.SequenceCap;
end

for imageIndex=1:imageCount
start = clock;
Settings.ResultPath = [Settings.InitialResultPath baseFolder '/']; % Set path to base folder
Results.QueryImageName = num2str(imageIndex);

if(strcmp(mode, 'test')) % Test mode
%if(~strcmp(inputImageList(imageIndex).name, '0445.jpg')) % To test specific image. Comment o/w.
% Settings.ResultPath = [Settings.InitialResultPath]; % Reset path
% continue;
%end
disp(['Processing ' inputImageList(imageIndex).name]);
imageFileName = inputImageList(imageIndex).name;
imageFullPath = strcat(Settings.QueryDataPath, imageFileName); % Construct the full path of the image
queryImage = imread(imageFullPath); % Read image
fileName = strrep(imageFileName, '.jpg', ''); % Strip file extension to obtain file name
fid = fopen([Settings.QueryDataPath fileName '.gps'], 'r'); % Read GPS data

if fid <= 0
error('Cannot read: %s', fileName);
end

tline = fgetl(fid);
fileNameParameterArray = textscan(tline, '%s', 'delimiter', ' '); % Split string
lat = fileNameParameterArray{1}{1};
lon = fileNameParameterArray{1}{2};
fclose(fid);
Settings.QueryImageLatitude = str2double(lat);
Settings.QueryImageLongitude = str2double(lon);
Results.QueryImageName = fileName;
else
queryImage = keyFrames(imageIndex);
end

mkdir(Settings.ResultPath, Results.QueryImageName); % Create a directory to save individual results.
Settings.ResultPath = [Settings.ResultPath Results.QueryImageName '/'];
[latitude, longitude, FirstCandidates, SecondCandidates, ThirdCandidates, FirstCandidateOutliers, SecondCandidateOutliers, AllCandidates] = RetrieveAlignPredict(queryImage, AllItems, Settings);
% Display Results
disp('---------RESULTS--------------------------------------------------------------------------------------');
disp(['Estimated location for image ' Results.QueryImageName]);
disp(['Latitude:' num2str(latitude)]);
disp(['Longitude:' num2str(longitude)]);
computationTime = etime(clock, start);
disp(['The computation took ' num2str(computationTime) ' seconds on the ' num2str(size(queryImage, 2)) 'x' num2str(size(queryImage, 1)) ' image']);

if(strcmp(mode,'test')) % Test mode
latlongQueryImage = [Settings.QueryImageLatitude Settings.QueryImageLongitude];
Results.EstimationError = lldistkm(latlongQueryImage, [latitude longitude]); % Calculate distance between estimated location and query location

if(Results.EstimationError < Settings.SuccessDistance)
Results.Success = 1;
disp('Estimation succeeded...');
else
Results.Success = 0;
disp('Estimation failed...');
end

disp(['Estimation error:' num2str(Results.EstimationError) 'km']);
disp('Please wait, calculating better than chance metric...');
[RandomCandidates, latitudeRandom, longitudeRandom] = EstimateByChance(AllCandidates, length(ThirdCandidates), Settings);
estimatedDistanceForRandomSelection = lldistkm(latlongQueryImage, [latitudeRandom longitudeRandom]); % Calculate distance between the query and the estimated location
Results.TimesBetterThanChance = estimatedDistanceForRandomSelection / Results.EstimationError;
disp(['Our results are better than chance by ' num2str(Results.TimesBetterThanChance) ' times']);
end
disp('--------------------------------------------------------------------------------------------------------');

if(Settings.DisplayResults == 1 || Settings.ExportResults == 1)
disp('Adjusting points..');
[AllCandidates, FirstCandidates, SecondCandidates] = AdjustCandidateScoresForPlotting(AllCandidates, FirstCandidates, SecondCandidates);
end

% Plot results
if(Settings.DisplayResults == 1)
disp('Plotting results..');
DisplayAndSaveResults(queryImage, FirstCandidates, SecondCandidates, ThirdCandidates, RandomCandidates, AllCandidates, FirstCandidateOutliers, SecondCandidateOutliers, Settings); % Display and save results altogether
close all;
end

Results.QueryImageLatitude = Settings.QueryImageLatitude; % Save results
Results.QueryImageLongitude = Settings.QueryImageLongitude;
Results.EstimatedLatitude = latitude;
Results.EstimatedLongitude = longitude;
Results.ComputationTime = computationTime;

if(Settings.ExportResults == 1)
save([Settings.ResultPath 'Settings.mat'], 'Settings');
save([Settings.ResultPath 'Results.mat'], 'Results');
save([Settings.ResultPath 'FirstCandidates.mat'], 'FirstCandidates');
save([Settings.ResultPath 'SecondCandidates.mat'], 'SecondCandidates');
save([Settings.ResultPath 'ThirdCandidates.mat'], 'ThirdCandidates');
save([Settings.ResultPath 'RandomCandidates.mat'], 'RandomCandidates');
save([Settings.ResultPath 'FirstCandidateOutliers.mat'], 'FirstCandidateOutliers');
save([Settings.ResultPath 'SecondCandidateOutliers.mat'], 'SecondCandidateOutliers');
save([Settings.ResultPath 'AllCandidates.mat'], 'AllCandidates');
close all;
end

% Set joint results
JointResults(imageIndex).QueryImageName = Results.QueryImageName;
JointResults(imageIndex).EstimationError = Results.EstimationError;
JointResults(imageIndex).ByChanceDistanceError = estimatedDistanceForRandomSelection;
JointResults(imageIndex).ComputationTime = Results.ComputationTime;
JointResults(imageIndex).TimesBetterThanChance = Results.TimesBetterThanChance;
JointResults(imageIndex).Success = Results.Success;
end

Settings.ResultPath = [Settings.InitialResultPath baseFolder '/']; % Reset path
save([Settings.ResultPath 'JointResults.mat'], 'JointResults');
struct2csv(JointResults, [Settings.ResultPath 'joint-recall-results-' Settings.ExperimentName '.csv']); % Save as csv file
averageEstimationError = mean([JointResults.EstimationError]);
disp('Geolocalization completed successfuly!');
end
78 changes: 78 additions & 0 deletions FurthestNeighbourRemoval.m
@@ -0,0 +1,78 @@
function [candidateLocations, outliers] = FurthestNeighbourRemoval(candidateLocations, method, Settings)

% Remove furthers neighbours in two stages by employing a similarity based and a distance based approach
%
% Inputs: candidateLocations - A set of candidates which contain inliers and outliers
% method - A similarity metric (JointScore or MatchScore)
% Settings - Application wide settings used to store algorithm parameters, paths etc.
%
% Outputs: candidateLocations - Inliers
% outliers - Outliers

remaining = length(candidateLocations);

%% PHASE 1: Remove furthest neighbours based on similarity.
minusFrom = 1;
if(strcmp(Settings.NormalizationMethod, 'exp'))
minusFrom = Settings.Sigma;
elseif(strcmp(Settings.NormalizationMethod, 'max'))
minusFrom = 1;
end

% Subtract scores, so that lower the values better the score.
for k = 1:length(candidateLocations);
if(strcmp(method, 'JointScore'))
candidateLocations(k).AdjustedDistance = minusFrom - candidateLocations(k).JointScore;
elseif(strcmp(method, 'MatchScore'))
candidateLocations(k).AdjustedDistance = minusFrom - candidateLocations(k).MatchScore;
end
candidateLocations(k).AveragePairwiseDistance = 0; % A small fix for first outliers to make them have same fields with second outliers
end

distMin = min([candidateLocations.AdjustedDistance]);
candidateLocations = nestedSortStruct(candidateLocations, 'AdjustedDistance'); % Sort by AdjustedDistance

idx = [];
for k = 1:length(candidateLocations)
if((candidateLocations(k).AdjustedDistance > (1 + Settings.Epsilon) * distMin))
if(remaining > Settings.NearestNeighbourNumber) % Make sure we have at least k items to triangulate.
idx = [idx k];
remaining = remaining - 1;
else
break;
end
end
end

outliersSimilarity = candidateLocations(idx);
candidateLocations(idx) = []; % Remove outliers

%% PHASE 2: Remove furthest neighbours based on 2D distances
positions = [candidateLocations.Latitude; candidateLocations.Longitude];
distances = dist(positions);
dMax = max(distances(:));
normalizedDistances = distances / dMax;

for k = 1:length(candidateLocations);
candidateLocations(k).AveragePairwiseDistance = mean(normalizedDistances(k,:));
candidateLocations(k).AdjustedDistance = 0; % A small fix for first outliers to make them have same fields with second outliers
end

candidateLocations = nestedSortStruct(candidateLocations, 'AveragePairwiseDistance'); % Sort by AveragePairwiseDistance
idx = [];
for k = length(candidateLocations) :-1:1
if(candidateLocations(k).AveragePairwiseDistance > Settings.NearestNeighbourThreshold)
if(remaining > Settings.NearestNeighbourNumber) % Make sure we have at least k items to triangulate.
idx = [idx k];
remaining = remaining - 1;
else
break;
end
end
end

outliers2D = candidateLocations(idx);
candidateLocations(idx) = []; % Remove outliers

outliers = [outliers2D, outliersSimilarity]; % Merge outliers obtained from two stages PHASE 1 and PHASE 2
end
11 changes: 11 additions & 0 deletions LoadSettings.m
@@ -0,0 +1,11 @@
function [settings] = LoadSettings(fileName)

% Load settings from ini file.
% Input : filename - name of the file
%
% Output : settings - a struct containing key value pairs

addpath('lib/ini2struct');
settings = ini2struct(fileName);
end

22 changes: 22 additions & 0 deletions NormalizeData.m
@@ -0,0 +1,22 @@
function normalizedData = NormalizeData(data, min, max, average, method, sigma)

% Normalize data
%
% Inputs: data - Input data to be normalized
% min - Minimum of the data range
% max - Maximum of the data range
% average - Average of the data range
% method - Method to use in normalization
% sigma - Sigma for exponential normalization
%
% Outputs: normalizedData - Normalized data

if(strcmp(method,'EXP'))
normalizedData = exp(-((data)^2 ./ (2 * (sigma * average)^2))); % Subtract from sigma so that higher values are better scores.
elseif(strcmp(method,'MAX'))
normalizedData = 1 - ((data - min) ./ (max - min));
else
normalizedData = 0;
disp('Error in normalization!!');
end
end
26 changes: 26 additions & 0 deletions PredictLocation.m
@@ -0,0 +1,26 @@
function [latitude, longitude] = PredictLocation(candidateLocations, method, Settings)

% Given a set of candidate locations return the most likely estimated location.
%
% Inputs: candidateLocations- Candidate locations is an array of latitude, longitude
% method - Similarity metric (JointScore or MatchScore)
% Settings - Application wide settings used to store algorithm parameters, paths etc.
%
% Outputs: latitude - Estimated latitude
% longitude - Estimated longitude

n = length(candidateLocations);
positions = [candidateLocations.Latitude; candidateLocations.Longitude];
if(strcmp(method, 'JointScore'))
subtractedScores = bsxfun(@minus, 1, [candidateLocations.JointScore]); % Subtract scores, so that lower the values better the score
elseif(strcmp(method, 'MatchScore'))
subtractedScores = bsxfun(@minus, 1, [candidateLocations.MatchScore]); % Subtract scores, so that lower the values better the score
else
return;
end

weightedPositions = bsxfun(@times, positions, subtractedScores);
sumOfScores = sum(subtractedScores);
latitude = sum(weightedPositions(1, : )) / sumOfScores;
longitude = sum(weightedPositions(2, : )) / sumOfScores;
end

0 comments on commit dfeef61

Please sign in to comment.