View Javadoc

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 }