1 /*
2 * @(#)$Id: Recogniser.java 796 2010-05-04 14:54:35Z bpuype $
3 *
4 * Author : Ueli Kurmann, igesture@uelikurmann.ch
5 *
6 * Purpose : The main recogniser component.
7 *
8 * -----------------------------------------------------------------------
9 *
10 * Revision Information:
11 *
12 * Date Who Reason
13 *
14 * Dec 26, 2006 ukurmann Initial Release
15 * Feb 24, 2007 bsigner Cleanup
16 *
17 * -----------------------------------------------------------------------
18 *
19 * Copyright 1999-2009 ETH Zurich. All Rights Reserved.
20 *
21 * This software is the proprietary information of ETH Zurich.
22 * Use is subject to license terms.
23 *
24 */
25
26
27 package org.ximtec.igesture;
28
29 import java.io.File;
30 import java.io.InputStream;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Set;
35 import java.util.concurrent.Executor;
36 import java.util.concurrent.Executors;
37 import java.util.logging.Logger;
38
39 import org.sigtec.ink.Note;
40 import org.sigtec.util.Constant;
41 import org.ximtec.igesture.algorithm.Algorithm;
42 import org.ximtec.igesture.algorithm.AlgorithmException;
43 import org.ximtec.igesture.algorithm.AlgorithmFactory;
44 import org.ximtec.igesture.configuration.Configuration;
45 import org.ximtec.igesture.core.Gesture;
46 import org.ximtec.igesture.core.GestureSample;
47 import org.ximtec.igesture.core.GestureSet;
48 import org.ximtec.igesture.core.Result;
49 import org.ximtec.igesture.core.ResultSet;
50 import org.ximtec.igesture.event.GestureHandler;
51 import org.ximtec.igesture.util.XMLTool;
52
53
54 /**
55 * The main recogniser component.
56 *
57 * @version 1.0, Dec 2006
58 * @author Ueli Kurmann, igesture@uelikurmann.ch
59 * @author Beat Signer, signer@inf.ethz.ch
60 */
61 public class Recogniser {
62
63 private static final int NUMBER_OF_THREADS = 6;
64
65 private static final Logger LOGGER = Logger.getLogger(Recogniser.class.getName());
66
67 private List<Algorithm> algorithms;
68
69 private Set<GestureHandler> gestureHandlers = new HashSet<GestureHandler>();
70 private Set<GestureHandler> multimodalGestureHandlers = new HashSet<GestureHandler>(); //multimodal gesture managers
71
72 // private boolean multimodalMode = false;
73 public static final int MIXED_MODE = 1;
74 public static final int MULTIMODAL_MODE = 2;
75 public static final int NORMAL_MODE = 0;
76 private int mode = NORMAL_MODE;
77
78
79 /**
80 * Creates a new recogniser.
81 *
82 * @param config the configuration object.
83 * @throws AlgorithmException if the recogniser could not be created.
84 */
85 public Recogniser(Configuration config) throws AlgorithmException {
86 algorithms = AlgorithmFactory.createAlgorithms(config);
87 }
88
89
90 /**
91 * Creates a new recogniser.
92 *
93 * @param config the configuration object.
94 * @param gestureHandler the gesture handler to be added.
95 * @throws AlgorithmException if the recogniser could not be created.
96 */
97 public Recogniser(Configuration config, GestureHandler gestureHandler)
98 throws AlgorithmException {
99 final Configuration clone = (Configuration)config.clone();
100 addGestureHandler(config.getGestureHandler());
101 clone.setGestureHandler(gestureHandler);
102 algorithms = AlgorithmFactory.createAlgorithms(clone);
103 }
104
105
106 /**
107 * Creates a new recogniser.
108 *
109 * @param config the configuration object.
110 * @param gestureSet the gesture set to be used.
111 * @throws AlgorithmException if the recogniser could not be created.
112 */
113 public Recogniser(Configuration config, GestureSet gestureSet)
114 throws AlgorithmException {
115 config.addGestureSet(gestureSet);
116 addGestureHandler(config.getGestureHandler());
117 algorithms = AlgorithmFactory.createAlgorithms(config);
118 }
119
120
121 /**
122 * Creates a new recogniser.
123 *
124 * @param config the input stream from which the XML configuration can be
125 * read.
126 * @throws AlgorithmException if the recogniser could not be created.
127 */
128 public Recogniser(InputStream config) throws AlgorithmException {
129 this(XMLTool.importConfiguration(config));
130 }
131
132
133 /**
134 * Creates a new recogniser.
135 *
136 * @param config the input stream from where the XML configuration can be
137 * read.
138 * @param set the input stream from where the gesture set in XML format can be
139 * read.
140 * @param gestureHandler the gesture handler to be informed about results.
141 * @throws AlgorithmException if the recogniser could not be created.
142 */
143 public Recogniser(InputStream config, InputStream set,
144 GestureHandler gestureHandler) throws AlgorithmException {
145 final Configuration configuration = XMLTool.importConfiguration(config);
146 configuration.setGestureHandler(gestureHandler);
147 configuration.addGestureSet(XMLTool.importGestureSet(set));
148 addGestureHandler(configuration.getGestureHandler());
149 algorithms = AlgorithmFactory.createAlgorithms(configuration);
150 }
151
152
153 /**
154 * Adds a gesture handler to the recogniser. The gesture handler's handle()
155 * method will be invoked every time a new ResultSet has been created (as part
156 * of a recognition process).
157 * @param gestureHandler the gesture handler to be added.
158 */
159 public void addGestureHandler(GestureHandler gestureHandler) {
160 gestureHandlers.add(gestureHandler);
161 } // addGestureHandler
162
163
164 /**
165 * Removes a gesture handler from the recogniser.
166 * @param gestureHandler the gesture handler to be removed.
167 */
168 public void removeGestureHandler(GestureHandler gestureHandler) {
169 gestureHandlers.remove(gestureHandler);
170 } // removeGestureHandler
171
172
173 /**
174 * Fires an event and informs all registered gesture handlers.
175 *
176 * @param resultSet the result set to be used as an argument for the fired
177 * event.
178 */
179 protected void fireEvent(final ResultSet resultSet) {
180
181 Set<GestureHandler> set = new HashSet<GestureHandler>();
182 switch(mode)
183 {
184 case MULTIMODAL_MODE:
185 set.addAll(multimodalGestureHandlers);
186 break;
187 case MIXED_MODE:
188 case NORMAL_MODE:
189 set.addAll(gestureHandlers);
190 }
191
192 Executor executor = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
193 for (final GestureHandler gestureHandler : set) {
194 LOGGER.info("Handler: "+gestureHandler.getClass());
195 if (gestureHandler != null) {
196 executor.execute(new Runnable() {
197
198 @Override
199 public void run() {
200 gestureHandler.handle(resultSet);
201 }
202
203 });
204 }
205 }
206 } // fireEvent
207
208
209 /**
210 * Recognises a gesture. The method uses all algorithms and returns a
211 * combination of the results returned by the different algorithms if
212 * 'recogniseAll' is set to true or the result of the first algorithm that
213 * recognised the given gesture if 'recogniseAll' is set to false.
214 *
215 * @param gesture the gesture to be recognised.
216 * @param recogniseAll true if the combination of all algorithms has to be
217 * returned, false if only the result of the first algorithm that
218 * recognises the result has to be returned.
219 * @return the result set containing the recognised gesture classes.
220 */
221 public ResultSet recognise(Gesture< ? > gesture, boolean recogniseAll) {
222 final ResultSet result = new ResultSet(this);
223
224 for (final Algorithm algorithm : algorithms) {
225
226 try {
227 for (final Result r : algorithm.recognise(gesture).getResults()) {
228 result.addResult(r);
229 }
230 }
231 catch (AlgorithmException e) {
232 LOGGER.info(e.getMessage());
233 }
234
235 if (!result.isEmpty() && !recogniseAll) {
236 break;
237 }
238
239 }
240 LOGGER.info(result.toString());
241
242 //MODIFY >
243
244 // based on the resultset, determine the gesture class of the gesture
245 List<Result> results = result.getResults();
246 Result maxResult = null;
247 double maxAccuracy = 0.0;
248
249 for (Iterator<Result> iterator = results.iterator(); iterator.hasNext();) {
250 Result r = iterator.next();
251 if(r.getAccuracy() > maxAccuracy)
252 {
253 maxAccuracy = r.getAccuracy();
254 maxResult = r;
255 }
256 }
257 //set the name of the gesture to that of the gesture class
258 if(maxResult != null)
259 {
260 gesture.setName(maxResult.getGestureClassName()+":"+maxResult.getGestureClass().getId());
261 // fireEvent(result);
262 }
263 else
264 gesture.setName("");
265 //MODIFY <
266
267 result.setGesture(gesture);
268 fireEvent(result);
269 return result;
270 } // recognise
271
272
273 /**
274 * Recognises a gesture. The method uses all registered algorithms and stops
275 * as soon as the first algorithm returns a result.
276 *
277 * @param gesture the gesture to be recognised.
278 * @return the result set containing the recognised gesture classes.
279 */
280 public ResultSet recognise(Gesture< ? > gesture) {
281 return recognise(gesture, false);
282 } // recognise
283
284
285 /**
286 * Recognises a gesture. The method uses all registered algorithms and stops
287 * as soon as the first algorithm returns a result.
288 *
289 * @param note the note to be recognised.
290 * @return the result set containing the recognised gesture classes.
291 */
292 public ResultSet recognise(Note note) {
293 return recognise(note, false);
294 } // recognise
295
296
297 /**
298 * Recognises a gesture. The method uses all algorithms and returns a
299 * combination of the results returned by the different algorithms if
300 * 'recogniseAll' is set to true or the result of the first algorithm that
301 * recognised the given note if 'recogniseAll' is set to false.
302 *
303 * @param note the note to be recognised.
304 * @param recogniseAll true if the combination of all algorithms has to be
305 * returned, false if only the result of the first algorithm that
306 * recognises the result has to be returned.
307 * @return the result set containing the recognised gesture classes.
308 */
309 public ResultSet recognise(Note note, boolean recogniseAll) {
310 return recognise(new GestureSample(Constant.EMPTY_STRING, note));
311 } // recognise
312
313
314 /*
315 * Returns the list of algorithms.
316 */
317 public List<Algorithm> getAlgorithms() {
318 return algorithms;
319 } // getAlgorithms
320
321
322 // FIXME: remove?
323 public static Recogniser newRecogniser(String configFile,
324 String gestureSetFile) throws AlgorithmException {
325 GestureSet gestureSet = XMLTool.importGestureSet(new File(gestureSetFile));
326 Configuration configuration = XMLTool.importConfiguration(new File(
327 configFile));
328 return new Recogniser(configuration, gestureSet);
329 }
330
331
332 /**
333 * Get the associated gesture handlers.
334 */
335 public Set<GestureHandler> getGestureHandlers()
336 {
337 return gestureHandlers;
338 }
339
340 /**
341 * Change the mode of this recogniser.
342 * If the recogniser is in multimodal mode, the gestures are first sent to the multimodal
343 * gesture manager that further handles the notification of interested listeners.
344 * If the recogniser is in normal mode, the gestures are fired immediately to the interested listeners.
345 * If the recogniser is in mixed mode, both behaviors are used.
346 * @param mode The value to set
347 */
348 public void setMode(int mode)
349 {
350 this.mode = mode;
351 }
352
353 /**
354 * Get the mode of this recogniser
355 * @return the mode
356 */
357 public int getMode() {
358 return mode;
359 }
360
361
362
363 /**
364 * Add a multimodal gesture handler to the recogniser.
365 */
366 public void addMultimodalGestureHandler(GestureHandler handler)
367 {
368 multimodalGestureHandlers.add(handler);
369 }
370
371 /**
372 * Remove a multimodal gesture handler from the recogniser
373 */
374 public void removeMultimodalGestureHandler(GestureHandler handler)
375 {
376 multimodalGestureHandlers.remove(handler);
377 }
378
379 }