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.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
52
53
54
55
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
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
115 maxResultSetSize = config.getMaxResultSetSize();
116 preprocess(GestureTool.combine(config.getGestureSets()));
117 }
118
119
120
121
122
123
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
132 signatures.add(new GestureSignature((Note)(sample.getGesture())
133 .clone(), gestureClass, rasterSize, gridSize));
134 }
135
136 }
137
138 }
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 }
191
192
193
194
195
196
197
198
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 }
204
205
206
207
208
209
210
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 }
227
228
229 @SuppressWarnings("unchecked")
230 public Enum[] getConfigParameters() {
231 return Config.values();
232 }
233
234 @Override
235 public int getType() {
236 return org.ximtec.igesture.util.Constant.TYPE_2D;
237 }
238
239 }