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 package org.ximtec.igesture.algorithm.rubine3d;
28
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Vector;
35 import java.util.logging.Logger;
36
37 import org.sigtec.ink.Note;
38 import org.sigtec.util.Constant;
39 import org.ximtec.igesture.Recogniser;
40 import org.ximtec.igesture.algorithm.AlgorithmException;
41 import org.ximtec.igesture.algorithm.SampleBasedAlgorithm;
42 import org.ximtec.igesture.algorithm.AlgorithmException.ExceptionType;
43 import org.ximtec.igesture.algorithm.feature.Feature;
44 import org.ximtec.igesture.algorithm.rubine.RubineAlgorithm;
45 import org.ximtec.igesture.algorithm.rubine.RubineConfiguration;
46 import org.ximtec.igesture.configuration.Configuration;
47 import org.ximtec.igesture.core.Gesture;
48 import org.ximtec.igesture.core.GestureClass;
49 import org.ximtec.igesture.core.GestureSample3D;
50 import org.ximtec.igesture.core.GestureSet;
51 import org.ximtec.igesture.core.Result;
52 import org.ximtec.igesture.core.ResultSet;
53 import org.ximtec.igesture.core.SampleDescriptor;
54 import org.ximtec.igesture.core.SampleDescriptor3D;
55 import org.ximtec.igesture.util.additions3d.RecordedGesture3D;
56
57 public class Rubine3DAlgorithm extends SampleBasedAlgorithm
58
59 private static final Logger LOGGER = Logger.getLogger(Rubine3DAlgorithm.class.getName());
60
61 private Rubine3DConfiguration rubine3dConfig;
62
63 private static final int PLANE_XY = 0;
64 private static final int PLANE_YZ = 1;
65 private static final int PLANE_ZX = 2;
66
67 private Map<GestureClass, GestureClass> gestureClassMapping;
68
69
70 private GestureSet setXY;
71 private GestureSet setYZ;
72 private GestureSet setZX;
73
74
75
76
77 public Rubine3DAlgorithm() {
78 setXY = new GestureSet();
79 setYZ = new GestureSet();
80 setZX = new GestureSet();
81 gestureClassMapping = new HashMap<GestureClass,GestureClass>();
82 }
83
84 @Override
85 public Enum<?>[] getConfigParameters() {
86 return Rubine3DConfiguration.Config.values();
87 }
88
89 @Override
90 public String getDefaultParameterValue(String parameterName) {
91 return Rubine3DConfiguration.getDefaultConfiguration().get(
92 parameterName);
93 }
94
95 @Override
96 public void init(Configuration configuration) throws AlgorithmException {
97 LOGGER.info("Rubine3DAlgorithm.init()");
98 this.rubine3dConfig = new Rubine3DConfiguration(configuration);
99
100 Iterator<GestureSet> i = configuration.getGestureSets().iterator();
101 while (i.hasNext()) {
102 GestureSet tempSet = i.next();
103 splitGestureSet(tempSet);
104 }
105 }
106
107
108
109
110
111 public ResultSet recognise(Gesture<?> gesture) throws AlgorithmException {
112
113 if (gesture instanceof GestureSample3D) {
114 return this.recognise((GestureSample3D) gesture);
115 } else {
116 throw new AlgorithmException(ExceptionType.Recognition);
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131 public ResultSet recognise(GestureSample3D gesture)
132 throws AlgorithmException {
133
134 List<Gesture<Note>> planes = gesture.splitToPlanes();
135
136 List<Double> weights = determinePlaneWeights();
137
138 Configuration configXY = createConfiguration(PLANE_XY);
139 Configuration configYZ = createConfiguration(PLANE_YZ);
140 Configuration configZX = createConfiguration(PLANE_ZX);
141
142 Recogniser recogniserXY = new Recogniser(configXY);
143 Recogniser recogniserYZ = new Recogniser(configYZ);
144 Recogniser recogniserZX = new Recogniser(configZX);
145
146 List<ResultSet> sets = new ArrayList<ResultSet>();
147 sets.add(recogniserXY.recognise(planes.get(0)));
148 sets.add(recogniserYZ.recognise(planes.get(1)));
149 sets.add(recogniserZX.recognise(planes.get(2)));
150
151 try {
152
153 ResultSet rs = combineResultSets(sets, weights);
154 List<Result> results = rs.getResults();
155 for (Iterator iterator = results.iterator(); iterator.hasNext();) {
156 Result result = (Result) iterator.next();
157 result.setGestureClass(gestureClassMapping.get(result.getGestureClass()));
158 }
159 return rs;
160 } catch (Exception e) {
161 e.printStackTrace();
162 }
163 return null;
164 }
165
166
167
168
169
170
171
172
173
174
175 private Configuration createConfiguration(int plane) {
176
177 Configuration recogniserConfig = new Configuration();
178 RubineConfiguration rubineConfig = null;
179
180
181 recogniserConfig.addAlgorithm(RubineAlgorithm.class.getName());
182
183 switch(plane)
184 {
185 case PLANE_XY:
186
187 recogniserConfig.addGestureSet(this.setXY);
188 rubineConfig = rubine3dConfig.getXyConfiguration();
189 break;
190 case PLANE_YZ:
191
192 recogniserConfig.addGestureSet(this.setYZ);
193 rubineConfig = rubine3dConfig.getYzConfiguration();
194 break;
195 case PLANE_ZX:
196
197 recogniserConfig.addGestureSet(this.setZX);
198 rubineConfig = rubine3dConfig.getZxConfiguration();
199 break;
200 default:
201
202
203 }
204
205
206
207
208 recogniserConfig.addParameter(RubineAlgorithm.class.getName(),
209 RubineConfiguration.Config.MAHALANOBIS_DISTANCE.name(), String
210 .valueOf(rubineConfig.getMahalanobisDistance()));
211 recogniserConfig.addParameter(RubineAlgorithm.class.getName(),
212 RubineConfiguration.Config.MIN_DISTANCE.name(), String
213 .valueOf(rubineConfig.getMinDistance()));
214 recogniserConfig.addParameter(RubineAlgorithm.class.getName(),
215 RubineConfiguration.Config.PROBABILITY.name(), String
216 .valueOf(rubineConfig.getProbability()));
217
218 Feature[] features = rubineConfig.getFeatureList();
219 StringBuilder sb = new StringBuilder();
220 for (int i = 0; i < features.length; i++) {
221 sb.append(features[i].getClass().getName());
222 sb.append(Constant.COMMA);
223 }
224
225 recogniserConfig.addParameter(RubineAlgorithm.class.getName(),
226 RubineConfiguration.Config.FEATURE_LIST.name(), sb.toString());
227
228
229 return recogniserConfig;
230 }
231
232
233
234
235
236
237
238
239 private List<Double> determinePlaneWeights() throws AlgorithmException {
240 List<Double> weights = new Vector<Double>();
241
242 if ((rubine3dConfig.getXyWeight() + rubine3dConfig.getYzWeight() + rubine3dConfig
243 .getZxWeight()) > 1.01
244 || (rubine3dConfig.getXyWeight() + rubine3dConfig.getYzWeight() + rubine3dConfig
245 .getZxWeight()) < 0.99) {
246 System.err.println("Weights do not add up to 1");
247 throw new AlgorithmException(
248 AlgorithmException.ExceptionType.Initialisation);
249 }
250
251 weights.add(rubine3dConfig.getXyWeight());
252 weights.add(rubine3dConfig.getYzWeight());
253 weights.add(rubine3dConfig.getZxWeight());
254
255 return weights;
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270 private ResultSet combineResultSets(List<ResultSet> sets,
271 List<Double> weights) throws Exception {
272
273 if (sets.size() != weights.size()) {
274 throw new Exception(
275 "Rubine3DAlgorithm.combineResultSets(): The number of ResultSets does not match the number of weights.");
276 }
277
278 ResultSet returnSet = combine(sets, weights);
279
280 returnSet = sortByAccuray(returnSet);
281
282 return returnSet;
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296 private ResultSet combine(List<ResultSet> sets, List<Double> weights) {
297
298
299 for (int i = 0; i < sets.get(0).getResults().size(); i++) {
300 sets.get(0).getResults().get(i).setAccuracy(
301 sets.get(0).getResults().get(i).getAccuracy()
302 * weights.get(0));
303 }
304
305 for (int i = 0; i < sets.get(1).getResults().size(); i++) {
306 sets.get(1).getResults().get(i).setAccuracy(
307 sets.get(1).getResults().get(i).getAccuracy()
308 * weights.get(1));
309 }
310
311 for (int i = 0; i < sets.get(2).getResults().size(); i++) {
312 sets.get(2).getResults().get(i).setAccuracy(
313 sets.get(2).getResults().get(i).getAccuracy()
314 * weights.get(2));
315 }
316
317 ResultSet returnSet = new ResultSet();
318
319
320 returnSet = sets.get(0);
321
322
323 for (int i = 0; i < sets.get(1).getResults().size(); i++) {
324
325 if (returnSet.contains(sets.get(1).getResult(i).getGestureClass())) {
326
327 for (int j = 0; j < returnSet.getResults().size(); j++) {
328 if (returnSet.getResults().get(j).getGestureClass()
329 .getName().equals(
330 sets.get(1).getResult(i).getGestureClass()
331 .getName())) {
332 returnSet.getResults().get(j).setAccuracy(
333 returnSet.getResults().get(j).getAccuracy()
334 + sets.get(1).getResult(i)
335 .getAccuracy());
336 }
337 }
338 } else {
339 returnSet.addResult(sets.get(1).getResult(i));
340 }
341 }
342
343
344 for (int i = 0; i < sets.get(2).getResults().size(); i++) {
345
346 if (returnSet.contains(sets.get(2).getResult(i).getGestureClass())) {
347
348 for (int j = 0; j < returnSet.getResults().size(); j++) {
349 if (returnSet.getResults().get(j).getGestureClass()
350 .getName().equals(
351 sets.get(2).getResult(i).getGestureClass()
352 .getName())) {
353 returnSet.getResults().get(j).setAccuracy(
354 returnSet.getResults().get(j).getAccuracy()
355 + sets.get(2).getResult(i)
356 .getAccuracy());
357 }
358 }
359 } else {
360 returnSet.addResult(sets.get(2).getResult(i));
361 }
362 }
363
364 double totalAccuracy = 0;
365 for (int i = 0; i < returnSet.getResults().size(); i++) {
366 totalAccuracy = totalAccuracy
367 + returnSet.getResult(i).getAccuracy();
368 }
369
370 if (totalAccuracy != 0 && totalAccuracy < 1) {
371 double factor = 1 / totalAccuracy;
372 for (int i = 0; i < returnSet.getResults().size(); i++) {
373 returnSet.getResults().get(i).setAccuracy(
374 returnSet.getResults().get(i).getAccuracy() * factor);
375 }
376 }
377
378 return returnSet;
379 }
380
381
382
383
384
385
386
387
388
389
390 private ResultSet sortByAccuray(ResultSet inputSet) {
391
392 ResultSet outputSet = new ResultSet();
393 if (inputSet.getResults().size() > 0) {
394 outputSet.addResult(inputSet.getResult(0));
395
396 for (int j = 0; j < inputSet.getResults().size(); j++) {
397 boolean added = false;
398
399 for (int k = 0; k < outputSet.getResults().size(); k++) {
400
401
402
403 if (inputSet.getResult(j).getAccuracy() > outputSet
404 .getResult(k).getAccuracy()) {
405
406
407 outputSet.getResults().add(k, inputSet.getResult(j));
408 added = true;
409 }
410 }
411
412
413
414 if (!added) {
415 outputSet.getResults().add(inputSet.getResult(j));
416 }
417 }
418 }
419
420 return outputSet;
421 }
422
423
424
425
426
427
428
429
430 private void splitGestureSet(GestureSet inputSet) {
431
432 setXY.setName(inputSet.getName());
433 setYZ.setName(inputSet.getName());
434 setZX.setName(inputSet.getName());
435
436 Iterator<GestureClass> classIter = inputSet.getGestureClasses()
437 .iterator();
438 while (classIter.hasNext()) {
439 GestureClass tempClass = classIter.next();
440 GestureClass classXY = new GestureClass(tempClass.getName());
441 gestureClassMapping.put(classXY, tempClass);
442 GestureClass classYZ = new GestureClass(tempClass.getName());
443 gestureClassMapping.put(classYZ, tempClass);
444 GestureClass classZX = new GestureClass(tempClass.getName());
445 gestureClassMapping.put(classZX, tempClass);
446
447 if (tempClass.getDescriptor(SampleDescriptor3D.class) != null) {
448 SampleDescriptor descXY = new SampleDescriptor();
449 SampleDescriptor descYZ = new SampleDescriptor();
450 SampleDescriptor descZX = new SampleDescriptor();
451
452 Iterator<Gesture<RecordedGesture3D>> sampleIter = tempClass
453 .getDescriptor(SampleDescriptor3D.class).getSamples()
454 .iterator();
455 while (sampleIter.hasNext()) {
456 GestureSample3D tempSample = (GestureSample3D) sampleIter
457 .next();
458
459 List<Gesture<Note>> planes = tempSample.splitToPlanes();
460
461 descXY.addSample(planes.get(0));
462 descYZ.addSample(planes.get(1));
463 descZX.addSample(planes.get(2));
464 }
465
466 classXY.addDescriptor(descXY);
467 classYZ.addDescriptor(descYZ);
468 classZX.addDescriptor(descZX);
469 }
470
471 setXY.addGestureClass(classXY);
472 setYZ.addGestureClass(classYZ);
473 setZX.addGestureClass(classZX);
474 }
475
476 }
477
478
479
480
481 @Override
482 public int getType() {
483 return org.ximtec.igesture.util.Constant.TYPE_3D;
484 }
485
486 }