add PCLOC annotations. all three benchmarks are type-checked now.
[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  * 
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with LEA. If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23  * 
24  * @author Florian
25  */
26 @LATTICE("CS<C,C*")
27 @METHODDEFAULT("OUT<THIS,THIS<IN,THISLOC=THIS,RETURNLOC=OUT")
28 public class ClassifierTree {
29
30   @LOC("CS")
31   private Classifier classifiers[];
32
33   public ClassifierTree(int size) {
34     classifiers = new Classifier[size];
35   }
36
37   public void addClassifier(@LOC("IN") int idx, @LOC("IN") Classifier c) {
38     classifiers[idx] = c;
39   }
40
41   /**
42    * Locates a face by searching radial starting at the last known position. If
43    * lastCoordinates are null we simply start in the center of the image.
44    * <p>
45    * TODO: This method could quite possible be tweaked so that face recognition
46    * would be much faster
47    * 
48    * @param image
49    *          the image to process
50    * @param lastCoordinates
51    *          the last known coordinates or null if unknown
52    * @return an rectangle representing the actual face position on success or
53    *         null if no face could be detected
54    */
55   @LATTICE("OUT<CXY,CXY<THIS,THIS<V,V<IMG,IMG<C,C<IN,C*,V*,FACTOR*,CXY*,THISLOC=THIS,RETURNLOC=OUT,GLOBALLOC=IN")
56   @PCLOC("C")
57   public Rectangle2D locateFaceRadial(@LOC("IN") Image smallImage,
58       @LOC("THIS,ClassifierTree.C") Rectangle2D lastCoordinates) {
59
60     @LOC("IMG") IntegralImageData imageData = new IntegralImageData(smallImage);
61     @LOC("IN") float originalImageFactor = 1;
62
63     if (lastCoordinates == null) {
64       // if we don't have a last coordinate we just begin in the center
65       @LOC("THIS,ClassifierTree.C") int smallImageMaxDimension =
66           Math.min(smallImage.getWidth(), smallImage.getHeight());
67       lastCoordinates =
68           new Rectangle2D((smallImage.getWidth() - smallImageMaxDimension) / 2.0,
69               (smallImage.getHeight() - smallImageMaxDimension) / 2.0, smallImageMaxDimension,
70               smallImageMaxDimension);
71       // System.out.println("lastCoordinates=" + lastCoordinates);
72     } else {
73       // first we have to scale the last coodinates back relative to the resized
74       // image
75       lastCoordinates =
76           new Rectangle2D((lastCoordinates.getX() * (1 / originalImageFactor)),
77               (lastCoordinates.getY() * (1 / originalImageFactor)),
78               (lastCoordinates.getWidth() * (1 / originalImageFactor)),
79               (lastCoordinates.getHeight() * (1 / originalImageFactor)));
80     }
81
82     @LOC("THIS,ClassifierTree.C") float startFactor = (float) (lastCoordinates.getWidth() / 100.0f);
83
84     // first we calculate the maximum scale factor for our 200x200 image
85     @LOC("THIS,ClassifierTree.C") float maxScaleFactor =
86         Math.min(imageData.getWidth() / 100f, imageData.getHeight() / 100f);
87     // maxScaleFactor = 1.0f;
88
89     // we simply won't recognize faces that are smaller than 40x40 px
90     @LOC("THIS,ClassifierTree.C") float minScaleFactor = 0.5f;
91
92     @LOC("THIS,ClassifierTree.C") float maxScaleDifference =
93         Math.max(Math.abs(maxScaleFactor - startFactor), Math.abs(minScaleFactor - startFactor));
94
95     // border for faceYes-possibility must be greater that that
96     @LOC("THIS,ClassifierTree.C") float maxBorder = 0.999f;
97
98     @LOC("THIS,ClassifierTree.C") int startPosX = (int) lastCoordinates.getX();
99     @LOC("THIS,ClassifierTree.C") int startPosY = (int) lastCoordinates.getX();
100
101     @LOC("THIS,ClassifierTree.C") int loopidx = 0;
102     TERMINATE: for (@LOC("THIS,ClassifierTree.C") float factorDiff = 0.0f; Math.abs(factorDiff) <= maxScaleDifference; factorDiff =
103         (factorDiff + sgn(factorDiff) * 0.1f) * -1 // we alternate between
104                                                    // negative and positiv
105                                                    // factors
106     ) {
107
108       if (++loopidx > 1000) {
109         return null;
110       }
111
112       @LOC("THIS,ClassifierTree.C") float factor = startFactor + factorDiff;
113       if (factor > maxScaleFactor || factor < minScaleFactor)
114         continue;
115
116       // now we calculate the actualDimmension
117       @LOC("THIS,ClassifierTree.C") int actualDimmension = (int) (100 * factor);
118       @LOC("THIS,ClassifierTree.C") int maxX = imageData.getWidth() - actualDimmension;
119       @LOC("THIS,ClassifierTree.C") int maxY = imageData.getHeight() - actualDimmension;
120
121       @LOC("THIS,ClassifierTree.C") int maxDiffX = Math.max(Math.abs(startPosX - maxX), startPosX);
122       @LOC("THIS,ClassifierTree.C") int maxDiffY = Math.max(Math.abs(startPosY - maxY), startPosY);
123
124       @LOC("CXY") int xidx = 0;
125       TERMINATE: for (@LOC("CXY") float xDiff = 0.1f; Math.abs(xDiff) <= maxDiffX; xDiff =
126           (xDiff + sgn(xDiff) * 0.5f) * -1) {
127
128         if (++xidx > 1000) {
129           return null;
130         }
131
132         @LOC("CXY") int xPos = Math.round((float) (startPosX + xDiff));
133
134         if (xPos < 0 || xPos > maxX)
135           continue;
136
137         @LOC("CXY") int yidx = 0;
138         // yLines:
139         TERMINATE: for (@LOC("CXY") float yDiff = 0.1f; Math.abs(yDiff) <= maxDiffY; yDiff =
140             (yDiff + sgn(yDiff) * 0.5f) * -1) {
141
142           if (++yidx > 1000) {
143             return null;
144           }
145
146           @LOC("CXY") int yPos = Math.round(startPosY + yDiff);
147           if (yPos < 0 || yPos > maxY)
148             continue;
149
150           // by now we should have a valid coordinate to process which we should
151           // do now
152           @LOC("CXY") boolean backToYLines = false;
153           for (@LOC("CXY") int idx = 0; idx < classifiers.length; ++idx) {
154             @LOC("CXY") float borderline =
155                 0.8f + (idx / (classifiers.length - 1)) * (maxBorder - 0.8f);
156             if (!classifiers[idx].classifyFace(imageData, factor, xPos, yPos, borderline)) {
157               backToYLines = true;
158               break;
159               // continue yLines;
160             }
161           }
162
163           // if we reach here we have a face recognized because our image went
164           // through all
165           // classifiers
166
167           if (backToYLines) {
168             continue;
169           }
170           @LOC("OUT") Rectangle2D faceRect =
171               new Rectangle2D(xPos * originalImageFactor, yPos * originalImageFactor,
172                   actualDimmension * originalImageFactor, actualDimmension * originalImageFactor);
173
174           return faceRect;
175
176         }
177
178       }
179
180     }
181
182     // System.out.println("Time: "+(System.currentTimeMillis()-timeStart)+"ms");
183     return null;
184
185   }
186
187   @LATTICE("OUT<IN,OUT<P,P<THIS,THISLOC=THIS,RETURNLOC=OUT")
188   @PCLOC("P")
189   private static int sgn(@LOC("IN") float value) {
190     return (value < 0 ? -1 : (value > 0 ? +1 : 1));
191   }
192
193 }