View Javadoc

1   /*
2    * @(#)$Id: SiGridAlgorithm.java 824 2010-05-26 22:38:01Z bpuype $
3    *
4    * Author       :   Ueli Kurmann, igesture@uelikurmann.ch
5    *
6    * Purpose      : 	Implementation of the signature algorithm.
7    *
8    * -----------------------------------------------------------------------
9    *
10   * Revision Information:
11   *
12   * Date             Who         Reason
13   *
14   * Dec 26, 2006     ukurmann    Initial Release
15   * Mar 18, 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.algorithm.signature;
28  
29  import java.util.ArrayList;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.logging.Logger;
34  
35  import org.sigtec.ink.Note;
36  import org.sigtec.util.Constant;
37  import org.ximtec.igesture.algorithm.AlgorithmTool;
38  import org.ximtec.igesture.algorithm.SampleBasedAlgorithm;
39  import org.ximtec.igesture.configuration.Configuration;
40  import org.ximtec.igesture.core.Gesture;
41  import org.ximtec.igesture.core.GestureClass;
42  import org.ximtec.igesture.core.GestureSample;
43  import org.ximtec.igesture.core.GestureSet;
44  import org.ximtec.igesture.core.Result;
45  import org.ximtec.igesture.core.ResultSet;
46  import org.ximtec.igesture.core.SampleDescriptor;
47  import org.ximtec.igesture.util.GestureTool;
48  
49  
50  /**
51   * Implementation of the signature algorithm.
52   * 
53   * @version 1.0 Dec 2006
54   * @author Ueli Kurmann, igesture@uelikurmann.ch
55   * @author Beat Signer, signer@inf.ethz.ch
56   */
57  public class SiGridAlgorithm extends SampleBasedAlgorithm {
58  
59     private static final Logger LOGGER = Logger
60           .getLogger(SiGridAlgorithm.class.getName());
61  
62     private List<GestureSignature> signatures;
63  
64     private int gridSize;
65  
66     private int rasterSize;
67  
68     private DistanceFunction distanceAlgorithm;
69  
70     private int maxResultSetSize;
71  
72     private double minAccuracy;
73  
74     private static final String DEFAULT_GRID_SIZE = "8";
75  
76     private static final String DEFAULT_RASTER_SIZE = "120";
77  
78     public enum Config {
79        GRID_SIZE, RASTER_SIZE, DISTANCE_FUNCTION, MIN_ACCURACY
80     }
81  
82     static {
83        /**
84         * Parameter Default Values
85         */
86        DEFAULT_CONFIGURATION.put(Config.GRID_SIZE.name(), DEFAULT_GRID_SIZE);
87        DEFAULT_CONFIGURATION.put(Config.RASTER_SIZE.name(), DEFAULT_RASTER_SIZE);
88        DEFAULT_CONFIGURATION.put(Config.DISTANCE_FUNCTION.name(),
89              HammingDistance.class.getName());
90        DEFAULT_CONFIGURATION.put(Config.MIN_ACCURACY.name(), "0.5");
91        
92     }
93  
94  
95     public SiGridAlgorithm() {
96     }
97  
98  
99     public void init(Configuration config) {
100       final Map<String, String> parameters = config.getParameters(this
101             .getClass().getCanonicalName());
102       gridSize = (int)AlgorithmTool.getDoubleParameterValue(Config.GRID_SIZE
103             .name(), parameters, DEFAULT_CONFIGURATION);
104       LOGGER.info(Config.GRID_SIZE.name() + Constant.COLON_BLANK + gridSize);
105       rasterSize = (int)AlgorithmTool.getDoubleParameterValue(Config.RASTER_SIZE
106             .name(), parameters, DEFAULT_CONFIGURATION);
107       LOGGER.info(Config.RASTER_SIZE.name() + Constant.COLON_BLANK + rasterSize);
108       distanceAlgorithm = createDistanceAlgorithm(AlgorithmTool
109             .getParameterValue(Config.DISTANCE_FUNCTION.name(), parameters,
110                   DEFAULT_CONFIGURATION));
111       minAccuracy = AlgorithmTool.getDoubleParameterValue(Config.MIN_ACCURACY
112             .name(), parameters, DEFAULT_CONFIGURATION);
113 
114       // minAccuracy = config.getMinAccuracy();
115       maxResultSetSize = config.getMaxResultSetSize();
116       preprocess(GestureTool.combine(config.getGestureSets()));
117    } // init
118 
119 
120    /**
121     * Creates sample signatures.
122     * 
123     * @param gestureSet the gesture set.
124     */
125    public void preprocess(GestureSet gestureSet) {
126       signatures = new ArrayList<GestureSignature>();
127 
128       for (final GestureClass gestureClass : gestureSet.getGestureClasses()) {
129 
130          for (Gesture<Note> sample : getSamples(gestureClass, SampleDescriptor.class)) {
131            // FIXME test 
132            signatures.add(new GestureSignature((Note)(sample.getGesture())
133                   .clone(), gestureClass, rasterSize, gridSize));
134          }
135 
136       }
137 
138    } // preprocess
139 
140 
141    public ResultSet recognise(Gesture<?> gesture) {
142       ResultSet resultSet = new ResultSet(maxResultSetSize);
143 
144       if (gesture instanceof GestureSample) {
145          Map<String, Result> tmpResults = new HashMap<String, Result>();
146 
147          Note note = ((GestureSample)gesture).getGesture();
148 
149          GestureSignature input = new GestureSignature((Note)note.clone(), null,
150                rasterSize, gridSize);
151          
152          
153          resultSet.setGesture(gesture);
154 
155          final int numOfBits = input.getBitStringLength()
156                * input.getNumberOfPoints();
157 
158          int minDistance = Integer.MAX_VALUE;
159 
160          for (GestureSignature signature : signatures) {
161             int d = distanceAlgorithm.computeDistance(input, signature);
162 
163             if (d < minDistance) {
164                minDistance = d;
165             }
166 
167             LOGGER.info(signature.getGestureClass().getName() + "[Distance = "
168                   + d + "; Accuracy = " + computeAccuracy(d, numOfBits) + "]");
169 
170             if (computeAccuracy(d, numOfBits) >= minAccuracy) {
171                String gestureName = signature.getGestureClass().getName();
172                if (!tmpResults.containsKey(gestureName)) {
173                   tmpResults.put(signature.getGestureClass().getName(),
174                         new Result(signature.getGestureClass(), computeAccuracy(
175                               d, numOfBits)));
176                }
177                else {
178                   Result result = tmpResults.get(signature.getGestureClass()
179                         .getName());
180                   result.setAccuracy(Math.max(result.getAccuracy(),
181                         computeAccuracy(d, numOfBits)));
182                }
183 
184             }
185          }
186          resultSet.addResults(tmpResults.values());
187       }
188 
189       return resultSet;
190    } // recognise
191 
192 
193    /**
194     * Computes the accuracy.
195     * 
196     * @param distance the distance.
197     * @param numOfBits the number of bits the signatures have.
198     * @return the accurracy.
199     */
200    private static double computeAccuracy(int distance, int numOfBits) {
201       final double accuracy = (1 - (double)distance / numOfBits);
202       return accuracy > 0 ? accuracy : 0;
203    } // computeAccuracy
204 
205 
206    /**
207     * Creates a new distance algorithm instance.
208     * 
209     * @param className
210     * @return the new distance algorithm instance.
211     */
212    private static DistanceFunction createDistanceAlgorithm(String className) {
213       try {
214          return (DistanceFunction)Class.forName(className.trim()).newInstance();
215       }
216       catch (final InstantiationException e) {
217          LOGGER.throwing(Constant.EMPTY_STRING, Constant.EMPTY_STRING, e);
218       }
219       catch (final IllegalAccessException e) {
220          LOGGER.throwing(Constant.EMPTY_STRING, Constant.EMPTY_STRING, e);
221       }
222       catch (final ClassNotFoundException e) {
223          LOGGER.throwing(Constant.EMPTY_STRING, Constant.EMPTY_STRING, e);
224       }
225       return null;
226    } // createDistanceAlgorithm
227 
228 
229    @SuppressWarnings("unchecked")
230    public Enum[] getConfigParameters() {
231       return Config.values();
232    } // getConfigParameters
233 
234 	@Override
235 	public int getType() {
236 		return org.ximtec.igesture.util.Constant.TYPE_2D;
237 	}
238 
239 }