wolffd@0
|
1 classdef MTTTagFeatureGenreBasic < MTTAudioFeature & handle
|
wolffd@0
|
2
|
wolffd@0
|
3
|
wolffd@0
|
4 properties(Constant = true)
|
wolffd@0
|
5
|
wolffd@0
|
6 my_revision = str2double(substr('$Rev: 99 $', 5, -1));
|
wolffd@0
|
7 end
|
wolffd@0
|
8
|
wolffd@0
|
9 % ---
|
wolffd@0
|
10 % here come the internal clip properties.
|
wolffd@0
|
11 % the database is stored as a global variable
|
wolffd@0
|
12 % ---
|
wolffd@0
|
13 properties
|
wolffd@0
|
14
|
wolffd@0
|
15 my_params = struct(...
|
wolffd@0
|
16 ... % ---
|
wolffd@0
|
17 ... % these are GenreBasic parameters
|
wolffd@0
|
18 ... % ---
|
wolffd@0
|
19 'pct_genres', 1, ... % 1/100 percentile genre tags used
|
wolffd@0
|
20 'empty_genres', 0 ... % allow empty genres to persist
|
wolffd@0
|
21 );
|
wolffd@0
|
22 end
|
wolffd@0
|
23
|
wolffd@0
|
24 methods
|
wolffd@0
|
25
|
wolffd@0
|
26 % ---
|
wolffd@0
|
27 % constructor: pointer to feature in database
|
wolffd@0
|
28 % ---
|
wolffd@0
|
29 function feature = MTTTagFeatureGenreBasic(varargin)
|
wolffd@0
|
30
|
wolffd@0
|
31 feature = feature@MTTAudioFeature(varargin{:});
|
wolffd@0
|
32 end
|
wolffd@0
|
33
|
wolffd@0
|
34 function data = extract(feature, clip)
|
wolffd@0
|
35 % process tag information and build the tag vector
|
wolffd@0
|
36
|
wolffd@0
|
37 % ---
|
wolffd@0
|
38 % get total number of tags.
|
wolffd@0
|
39 %
|
wolffd@0
|
40 % NOTE: the highest tag id should match the size of the
|
wolffd@0
|
41 % tagdb lexicon
|
wolffd@0
|
42 % ---
|
wolffd@0
|
43 % num_tags = clip.my_db.genredb.size();
|
wolffd@0
|
44
|
wolffd@0
|
45 if feature.my_params.pct_genres ~= 0
|
wolffd@0
|
46 % no tags, f.e. for parameter experiments in
|
wolffd@0
|
47 % higher level features
|
wolffd@0
|
48 [tagids, score] = clip.my_db.genredb.annotids_for_owner(clip.id);
|
wolffd@0
|
49
|
wolffd@0
|
50 % save lexicon
|
wolffd@0
|
51 data.lexicon = clip.my_db.genredb.lexicon;
|
wolffd@0
|
52
|
wolffd@0
|
53 % save to data structure
|
wolffd@0
|
54 data.tags.ids = tagids;
|
wolffd@0
|
55 data.tags.scores = score;
|
wolffd@0
|
56 end
|
wolffd@0
|
57
|
wolffd@0
|
58 % save info data
|
wolffd@0
|
59 data.info.type = 'MTTTagFeatureGenreBasic';
|
wolffd@0
|
60 data.info.owner = clip;
|
wolffd@0
|
61 data.info.owner_id = clip.id;
|
wolffd@0
|
62 data.info.creatorrev = feature.my_revision;
|
wolffd@0
|
63
|
wolffd@0
|
64 % save parameters
|
wolffd@0
|
65 data.info.params = feature.my_params;
|
wolffd@0
|
66
|
wolffd@0
|
67 data.final.vector = [];
|
wolffd@0
|
68 data.final.vector_info = struct();
|
wolffd@0
|
69 data.final.dim = 0;
|
wolffd@0
|
70 end
|
wolffd@0
|
71
|
wolffd@0
|
72
|
wolffd@0
|
73 % ---
|
wolffd@0
|
74 % NOTE: the following transforms are just stated fro
|
wolffd@0
|
75 % future use by now
|
wolffd@0
|
76 % ---
|
wolffd@0
|
77 function define_global_transform(features)
|
wolffd@0
|
78 % ---
|
wolffd@0
|
79 % compute the relevant tags, and save
|
wolffd@0
|
80 % them in the commom place
|
wolffd@0
|
81 % ---
|
wolffd@0
|
82
|
wolffd@0
|
83 % compute extreme cases
|
wolffd@0
|
84 if features(1).my_params.pct_genres == 1 && features(1).my_params.empty_genres
|
wolffd@0
|
85 % all tags allowed
|
wolffd@0
|
86
|
wolffd@0
|
87 common.rel_dimensions.tags.ids = 1:numel(features(1).data.lexicon);
|
wolffd@0
|
88 common.rel_dimensions.tags.id_pos = 1:numel(features(1).data.lexicon);
|
wolffd@0
|
89
|
wolffd@0
|
90 % set common feature values
|
wolffd@0
|
91 features(1).my_db.set_common(common);
|
wolffd@0
|
92 return;
|
wolffd@0
|
93
|
wolffd@0
|
94 elseif features(1).my_params.pct_genres == 0
|
wolffd@0
|
95 % no tags, f.e. for parameter experiments in
|
wolffd@0
|
96 % higher level features
|
wolffd@0
|
97
|
wolffd@0
|
98 common.rel_dimensions.tags.ids = [];
|
wolffd@0
|
99 common.rel_dimensions.tags.id_pos = [];
|
wolffd@0
|
100
|
wolffd@0
|
101 % set common feature values
|
wolffd@0
|
102 features(1).my_db.set_common(common);
|
wolffd@0
|
103 return;
|
wolffd@0
|
104 end
|
wolffd@0
|
105
|
wolffd@0
|
106
|
wolffd@0
|
107 allids = sparse(numel(features), numel(features(1).data.lexicon));
|
wolffd@0
|
108 for i = 1:numel(features)
|
wolffd@0
|
109
|
wolffd@0
|
110 allids(i,features(i).data.tags.ids) = ...
|
wolffd@0
|
111 allids(i,features(i).data.tags.ids) + features(i).data.tags.scores;
|
wolffd@0
|
112 end
|
wolffd@0
|
113
|
wolffd@0
|
114 % ---
|
wolffd@0
|
115 % get usage of tags and filter not-used tags
|
wolffd@0
|
116 % ---
|
wolffd@0
|
117 tagsum = sum(allids, 1);
|
wolffd@0
|
118 nonzero = tagsum > 0;
|
wolffd@0
|
119
|
wolffd@0
|
120 % ---
|
wolffd@0
|
121 % NOTE: We remove the empty genres, then
|
wolffd@0
|
122 % sort by weight / number of appearance and cut off
|
wolffd@0
|
123 ids = find(nonzero);
|
wolffd@0
|
124 [null, idx] = sort(tagsum(ids),'descend');
|
wolffd@0
|
125 ids = ids(idx);
|
wolffd@0
|
126
|
wolffd@0
|
127 % cutoff
|
wolffd@0
|
128 num_tags = ceil( features(1).my_params.pct_genres * numel(ids));
|
wolffd@0
|
129 valid_ids = ids(1:min(end, num_tags));
|
wolffd@0
|
130
|
wolffd@0
|
131 % ---
|
wolffd@0
|
132 % NOTE: make sure that the positions for the tags
|
wolffd@0
|
133 % stay correctly assigned / consistent
|
wolffd@0
|
134 % ---
|
wolffd@0
|
135 id_pos = sparse(size(valid_ids));
|
wolffd@0
|
136 id_pos(valid_ids) = 1:num_tags;
|
wolffd@0
|
137
|
wolffd@0
|
138 % save to common data structure
|
wolffd@0
|
139 common.rel_dimensions.tags.ids = valid_ids;
|
wolffd@0
|
140 common.rel_dimensions.tags.id_pos = id_pos;
|
wolffd@0
|
141
|
wolffd@0
|
142 % set common feature values
|
wolffd@0
|
143 features(1).my_db.set_common(common);
|
wolffd@0
|
144 end
|
wolffd@0
|
145
|
wolffd@0
|
146 function finalise(features)
|
wolffd@0
|
147
|
wolffd@0
|
148 for i = 1:numel(features)
|
wolffd@0
|
149
|
wolffd@0
|
150 % check for neccesary parameters
|
wolffd@0
|
151 if isempty(features(i).my_db.commondb)
|
wolffd@0
|
152
|
wolffd@0
|
153 error('Define the global transformation first')
|
wolffd@0
|
154 return;
|
wolffd@0
|
155 end
|
wolffd@0
|
156
|
wolffd@0
|
157 if features(i).my_params.pct_genres == 0
|
wolffd@0
|
158 vector_info.labels = {};
|
wolffd@0
|
159
|
wolffd@0
|
160 % save into feature struct
|
wolffd@0
|
161 features(i).data.final.dim = 0;
|
wolffd@0
|
162 features(i).data.final.vector = [];
|
wolffd@0
|
163 features(i).data.final.vector_info = vector_info;
|
wolffd@0
|
164 return;
|
wolffd@0
|
165 end
|
wolffd@0
|
166 % get valid tag ids
|
wolffd@0
|
167 valid_ids = features(i).common.rel_dimensions.tags.ids;
|
wolffd@0
|
168 num_tags = numel(valid_ids);
|
wolffd@0
|
169
|
wolffd@0
|
170 % ---
|
wolffd@0
|
171 % get vector positions for contined ids,
|
wolffd@0
|
172 % and sort out the non_allowed id's
|
wolffd@0
|
173 % ---
|
wolffd@0
|
174 id_pos = features(i).common.rel_dimensions.tags.id_pos;
|
wolffd@0
|
175
|
wolffd@0
|
176 [has_ids, has_pos] = intersect(features(i).data.tags.ids, valid_ids);
|
wolffd@0
|
177
|
wolffd@0
|
178 score = features(i).data.tags.scores;
|
wolffd@0
|
179
|
wolffd@0
|
180 % create feature vector
|
wolffd@0
|
181 vector = zeros(num_tags,1);
|
wolffd@0
|
182 vector(id_pos(has_ids)) = score(has_pos);
|
wolffd@0
|
183
|
wolffd@0
|
184 % ---
|
wolffd@0
|
185 % NOTE: this labelling costs to much space
|
wolffd@0
|
186 % ---
|
wolffd@0
|
187 vector_info.labels = features(i).data.lexicon(valid_ids);
|
wolffd@0
|
188
|
wolffd@0
|
189 % save into feature struct
|
wolffd@0
|
190 features(i).data.final.dim = num_tags;
|
wolffd@0
|
191 features(i).data.final.vector = vector;
|
wolffd@0
|
192 features(i).data.final.vector_info = vector_info;
|
wolffd@0
|
193 end
|
wolffd@0
|
194 end
|
wolffd@0
|
195
|
wolffd@0
|
196 function [a1] = visualise(feature)
|
wolffd@0
|
197
|
wolffd@0
|
198 % get tag descriptions form first clip
|
wolffd@0
|
199 tags = MTTClip(feature(1).owner_id()).my_db.genres;
|
wolffd@0
|
200
|
wolffd@0
|
201 % works for multiple feature instances
|
wolffd@0
|
202 for i = 1:numel(feature)
|
wolffd@0
|
203
|
wolffd@0
|
204 clip = MTTClip(feature(i).owner_id());
|
wolffd@0
|
205
|
wolffd@0
|
206 % plot feature data
|
wolffd@0
|
207 h = bar(feature(i).data.final.vector);
|
wolffd@0
|
208 a1 = gca;
|
wolffd@0
|
209
|
wolffd@0
|
210 set(a1,'XTick', 1:feature(i).data.final.dim,...
|
wolffd@0
|
211 'XTickLabel', tags);
|
wolffd@0
|
212 title(sprintf('clip %d: %s by %s, genres', ...
|
wolffd@0
|
213 clip.id, clip.title(),clip.artist()));
|
wolffd@0
|
214 end
|
wolffd@0
|
215 end
|
wolffd@0
|
216
|
wolffd@0
|
217 end
|
wolffd@0
|
218 end |