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