3c7c94e682062db2be33dcc4b3481df6b99c8dc4
[IRC.git] / Robust / src / Benchmarks / SSJava / EyeTracking / ClassifierTree.java
1 import SSJava.PCLOC;
2
3 /*
4  * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
5  * 
6  * This file is part of LEA.
7  * 
8  * LEA is free software: you can redistribute it and/or modify it under the
9  * terms of the GNU Lesser General Public License as published by the Free
10  * Software Foundation, either version 3 of the License, or (at your option) any
11  * later version.
12  * 
13  * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
14  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15  * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *   private Point readEyes(@LOC("IN") Image image, @LOC("IN") Rectangle2D rect) {
18  @LOC("OUT") EyeDetector ed = new EyeDetector(image, rect);
19  return ed.detectEye();
20  }
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with LEA. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * 
27  * @author Florian
28  */
29 @LATTICE("C<CS,CS<CUR,CUR<PREV,PREV<SIZE,PREV*,C*,CUR*")
30 @METHODDEFAULT("OUT<THIS,THIS<IN,THISLOC=THIS,RETURNLOC=OUT")
31 public class ClassifierTree {
32
33   @LOC("CS")
34   private Classifier classifiers[];
35
36   @LOC("CUR")
37   double x;
38   @LOC("CUR")
39   double y;
40   @LOC("CUR")
41   double width;
42   @LOC("CUR")
43   double height;
44
45   @LOC("SIZE")
46   int size;
47
48   @LATTICE("THIS<IN,THISLOC=THIS")
49   public ClassifierTree(@LOC("IN") int size) {
50     this.size = size;
51     classifiers = new Classifier[size];
52     x = -1;
53     y = -1;
54     width = -1;
55     height = -1;
56   }
57
58   public void addClassifier(@LOC("IN") int idx, @LOC("IN") Classifier c) {
59     classifiers[idx] = c;
60   }
61
62   /**
63    * Locates a face by searching radial starting at the last known position. If lastCoordinates are
64    * null we simply start in the center of the image.
65    * <p>
66    * TODO: This method could quite possible be tweaked so that face recognition would be much faster
67    * 
68    * @param image
69    *          the image to process
70    * @param lastCoordinates
71    *          the last known coordinates or null if unknown
72    * @return an rectangle representing the actual face position on success or null if no face could
73    *         be detected
74    */
75   @LATTICE("OUT<CXY,CXY<THIS,THIS<V,V<IMG,IMG<C,C<IN,C*,V*,FACTOR*,CXY*,THISLOC=THIS,RETURNLOC=OUT,GLOBALLOC=IN")
76   public void locateFaceRadial(@LOC("IN") Image smallImage) {
77
78     @LOC("THIS,ClassifierTree.CUR") double px = x;
79     @LOC("THIS,ClassifierTree.CUR") double py = y;
80     @LOC("THIS,ClassifierTree.CUR") double pwidth = width;
81     @LOC("THIS,ClassifierTree.CUR") double pheight = height;
82
83     x = -1;
84     y = -1;
85     width = -1;
86     height = -1;
87
88     @LOC("IMG") IntegralImageData imageData = new IntegralImageData(smallImage);
89     @LOC("IN") float originalImageFactor = 1;
90     if (px == -1) {
91       // if(true){
92       // if we don't have a last coordinate we just begin in the center
93       @LOC("THIS,ClassifierTree.PREV") int smallImageMaxDimension =
94           Math.min(smallImage.getWidth(), smallImage.getHeight());
95
96       px = (smallImage.getWidth() - smallImageMaxDimension) / 2.0;
97       py = (smallImage.getHeight() - smallImageMaxDimension) / 2.0;
98       pwidth = smallImageMaxDimension;
99       pheight = smallImageMaxDimension;
100     } else {
101       // first we have to scale the last coodinates back relative to the resized
102       // image
103       px = px * (1 / originalImageFactor);
104       py = py * (1 / originalImageFactor);
105       pwidth = pwidth * (1 / originalImageFactor);
106       pheight = pheight * (1 / originalImageFactor);
107     }
108
109
110     @LOC("THIS,ClassifierTree.CUR") float startFactor = (float) (pwidth / 100.0f);
111
112     // first we calculate the maximum scale factor for our 200x200 image
113     @LOC("THIS,ClassifierTree.CUR") float maxScaleFactor =
114         Math.min(imageData.getWidth() / 100f, imageData.getHeight() / 100f);
115     // maxScaleFactor = 1.0f;
116
117     // we simply won't recognize faces that are smaller than 40x40 px
118     @LOC("THIS,ClassifierTree.CUR") float minScaleFactor = 0.5f;
119
120     @LOC("THIS,ClassifierTree.CUR") float maxScaleDifference =
121         Math.max(Math.abs(maxScaleFactor - startFactor), Math.abs(minScaleFactor - startFactor));
122
123     // border for faceYes-possibility must be greater that that
124     @LOC("THIS,ClassifierTree.CUR") float maxBorder = 0.999f;
125
126     @LOC("THIS,ClassifierTree.CUR") int startPosX = (int) px;
127     @LOC("THIS,ClassifierTree.CUR") int startPosY = (int) py;
128
129     @LOC("THIS,ClassifierTree.CUR") int loopidx = 0;
130     TERMINATE: for (@LOC("THIS,ClassifierTree.CUR") float factorDiff = 0.0f; Math.abs(factorDiff) <= maxScaleDifference; factorDiff =
131         (factorDiff + sgn(factorDiff) * 0.1f) * -1 // we alternate between
132                                                    // negative and positiv
133                                                    // factors
134     ) {
135
136       if (++loopidx > 1000) {
137         px = -1;
138         py = -1;
139         pwidth = -1;
140         pheight = -1;
141         return;
142       }
143
144       @LOC("THIS,ClassifierTree.CUR") float factor = startFactor + factorDiff;
145       if (factor > maxScaleFactor || factor < minScaleFactor)
146         continue;
147
148       // now we calculate the actualDimmension
149       @LOC("THIS,ClassifierTree.CUR") int actualDimmension = (int) (100 * factor);
150       @LOC("THIS,ClassifierTree.CUR") int maxX = imageData.getWidth() - actualDimmension;
151       @LOC("THIS,ClassifierTree.CUR") int maxY = imageData.getHeight() - actualDimmension;
152
153       @LOC("THIS,ClassifierTree.CUR") int maxDiffX =
154           Math.max(Math.abs(startPosX - maxX), startPosX);
155       @LOC("THIS,ClassifierTree.CUR") int maxDiffY =
156           Math.max(Math.abs(startPosY - maxY), startPosY);
157
158       @LOC("THIS,ClassifierTree.CUR") int xidx = 0;
159       TERMINATE: for (@LOC("THIS,ClassifierTree.CUR") float xDiff = 0.1f; Math.abs(xDiff) <= maxDiffX; xDiff =
160           (xDiff + sgn(xDiff) * 0.5f) * -1) {
161
162         if (++xidx > 1000) {
163           px = -1;
164           py = -1;
165           pwidth = -1;
166           pheight = -1;
167           return;
168         }
169
170         @LOC("THIS,ClassifierTree.CUR") int xPos = Math.round((float) (startPosX + xDiff));
171
172         if (xPos < 0 || xPos > maxX)
173           continue;
174
175         @LOC("THIS,ClassifierTree.CUR") int yidx = 0;
176         // yLines:
177         TERMINATE: for (@LOC("THIS,ClassifierTree.CUR") float yDiff = 0.1f; Math.abs(yDiff) <= maxDiffY; yDiff =
178             (yDiff + sgn(yDiff) * 0.5f) * -1) {
179
180           if (++yidx > 1000) {
181             px = -1;
182             py = -1;
183             pwidth = -1;
184             pheight = -1;
185             return;
186           }
187
188           @LOC("THIS,ClassifierTree.CUR") int yPos = Math.round(startPosY + yDiff);
189           if (yPos < 0 || yPos > maxY)
190             continue;
191
192           // by now we should have a valid coordinate to process which we should
193           // do now
194           @LOC("THIS,ClassifierTree.C") boolean backToYLines = false;
195           for (@LOC("THIS,ClassifierTree.CUR") int idx = 0; idx < size; ++idx) {
196             @LOC("THIS,ClassifierTree.CUR") float borderline =
197                 0.8f + (idx / (size - 1)) * (maxBorder - 0.8f);
198             if (!classifiers[idx].classifyFace(imageData, factor, xPos, yPos, borderline)) {
199               backToYLines = true;
200               break;
201               // continue yLines;
202             }
203           }
204
205           // if we reach here we have a face recognized because our image went
206           // through all
207           // classifiers
208
209           if (backToYLines) {
210             continue;
211           }
212
213           x = xPos * originalImageFactor;
214           y = yPos * originalImageFactor;
215           width = actualDimmension * originalImageFactor;
216           height = actualDimmension * originalImageFactor;
217           return;
218
219         }
220
221       }
222
223     }
224
225     // System.out.println("Time: "+(System.currentTimeMillis()-timeStart)+"ms");
226     // return null;
227
228   }
229
230   @LATTICE("OUT<IN,OUT<P,P<THIS,THISLOC=THIS,RETURNLOC=OUT")
231   @PCLOC("P")
232   private static int sgn(@LOC("IN") float value) {
233     return (value < 0 ? -1 : (value > 0 ? +1 : 1));
234   }
235
236   @LATTICE("OUT<P,P<ED,ED<V,V<THIS,THIS<IN,V*,THISLOC=THIS,RETURNLOC=OUT,GLOBALLOC=IN")
237   public FaceAndEyePosition getEyePosition(@LOC("IN") Image image) {
238     if (image == null) {
239       return null;
240     }
241
242     @LOC("IN") float originalImageFactor = 1;
243
244     locateFaceRadial(image);
245
246     if (width > image.getWidth() || height > image.getHeight()) {
247       return null;
248     }
249
250     @LOC("OUT") EyePosition eyePosition = null;
251
252     if (x != -1) {
253       @LOC("ED") EyeDetector ed = new EyeDetector(image, x, y, width, height);
254       @LOC("P") Point point = ed.detectEye();
255       if (point != null) {
256         eyePosition = new EyePosition(point.getX(), point.getY());
257       }
258     }
259
260     System.out.println("eyePosition=" + eyePosition);
261
262     @LOC("OUT") FaceAndEyePosition fep = new FaceAndEyePosition(x, y, width, height, eyePosition);
263
264     return fep;
265   }
266
267
268 }