-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathEvaluatorDistance.m
117 lines (89 loc) · 4.26 KB
/
EvaluatorDistance.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
classdef EvaluatorDistance < Evaluator
%EVALUATORDISTANCE Summary of this class goes here
% Detailed explanation goes here
properties
top_matches = 10;
end
methods
function EV = EvaluatorDistance(network, database, layer)
if ~exist('layer', 'var')
layer = [];
end
EV@Evaluator(network, database, layer);
end
function pruned_features = pruneFeatures(EV, features)
% slightly lower threshold
threshold = 0.99 * EV.db.threshold;
% calculate distances
distances = sqrt(mean(diff(features, 1, 2) .^ 2, 1));
% prune features
to_save = distances > threshold;
pruned_features = features(:, [true to_save]);
end
function [match, score] = matchFeatures(EV, pruned_features)
% distances
distances = sqrt(sum(bsxfun(@(a, b) (a - b) .^ 2, pruned_features(:, 1), EV.db.data_features), 1));
% normalizing constant for scores
norm = max(EV.db.data_distances); % sqrt(sum(pruned_features .^ 2));
% TODO: potentially select one distance per video id
% sort top distances
[distances, idx] = sort(distances);
% start of all matching segments
match_starts = idx(1:EV.top_matches);
% matches
matches_video_id = zeros(1, length(match_starts));
matches_timestamp = zeros(1, length(match_starts));
matches_scores = nan(1, length(match_starts));
% list of matches
for i = 1:length(match_starts)
% score number of matching frames
score = max(norm - distances(i), 0) / norm;
% start
match_start = match_starts(i);
% get remaining video frames
cur_video_id = EV.db.data_video_ids(match_start);
% already processed
if ismember(cur_video_id, matches_video_id)
continue;
end
% get remaining frames
remaining_frames = sum(EV.db.data_video_ids((match_start+1):end) == cur_video_id);
% score remaining frames
if 0 < remaining_frames
remaining_features = EV.db.data_features(:, (match_start + 1):(match_start + remaining_frames));
score = score + EV.matchRemainingFeatures(pruned_features(:, 2:end), remaining_features, norm);
end
% store match
matches_video_id(i) = cur_video_id;
matches_timestamp(i) = EV.db.data_timestamps(match_start);
matches_scores(i) = score;
end
% get best match
[score, idx] = max(matches_scores);
% normalize best score
score = score / size(pruned_features, 2);
% make match structure
match = struct('video', EV.db.videos(matches_video_id(idx)), 'video_id', matches_video_id(idx), 'timestamp', matches_timestamp(idx));
end
end
methods (Access=protected)
function score = matchRemainingFeatures(EV, remaining_pruned_features, remaining_video_features, norm)
score = 0;
fn = @(a, b) (a - b) .^ 2;
last = 0;
for i = 1:min(size(remaining_pruned_features, 2), size(remaining_video_features, 2))
% distances
distances = sqrt(sum(bsxfun(fn, remaining_pruned_features(:, i), remaining_video_features), 1));
% get lowest distance
[cur_score, cur] = min(distances);
cur_score = max(norm - cur_score, 0) / norm;
% not sequential
if cur < last
cur_score = cur_score * 0.5;
end
last = cur;
score = score + cur_score;
end
end
end
end