4 * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
6 * This file is part of LEA.
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
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
17 * private Point readEyes( Image image, Rectangle2D rect) {
18 EyeDetector ed = new EyeDetector(image, rect);
19 return ed.detectEye();
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/>.
31 public class ClassifierTree {
34 private Classifier[] classifiers;
48 public ClassifierTree( int size) {
50 classifiers = new Classifier[size];
57 public void addClassifier( int idx, Classifier c) {
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.
66 * TODO: This method could quite possible be tweaked so that face recognition would be much faster
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
76 public void locateFaceRadial( Image smallImage) {
80 double pwidth = width;
81 double pheight = height;
88 IntegralImageData imageData = new IntegralImageData(smallImage);
89 float originalImageFactor = 1;
92 // if we don't have a last coordinate we just begin in the center
93 int smallImageMaxDimension = Math.min(smallImage.getWidth(), smallImage.getHeight());
95 px = (smallImage.getWidth() - smallImageMaxDimension) / 2.0;
96 py = (smallImage.getHeight() - smallImageMaxDimension) / 2.0;
97 pwidth = smallImageMaxDimension;
98 pheight = smallImageMaxDimension;
100 // first we have to scale the last coodinates back relative to the resized
102 px = px * (1 / originalImageFactor);
103 py = py * (1 / originalImageFactor);
104 pwidth = pwidth * (1 / originalImageFactor);
105 pheight = pheight * (1 / originalImageFactor);
109 float startFactor = (float) (pwidth / 100.0f);
111 // first we calculate the maximum scale factor for our 200x200 image
112 float maxScaleFactor = Math.min(imageData.getWidth() / 100f, imageData.getHeight() / 100f);
113 // maxScaleFactor = 1.0f;
115 // we simply won't recognize faces that are smaller than 40x40 px
116 float minScaleFactor = 0.5f;
118 float maxScaleDifference = Math.max(Math.abs(maxScaleFactor - startFactor), Math.abs(minScaleFactor - startFactor));
120 // border for faceYes-possibility must be greater that that
121 float maxBorder = 0.999f;
123 int startPosX = (int) px;
124 int startPosY = (int) py;
127 TERMINATE: for ( float factorDiff = 0.0f; Math.abs(factorDiff) <= maxScaleDifference; factorDiff =
128 (factorDiff + sgn(factorDiff) * 0.1f) * -1 // we alternate between
129 // negative and positiv
133 if (++loopidx > 1000) {
141 float factor = startFactor + factorDiff;
142 if (factor > maxScaleFactor || factor < minScaleFactor)
145 // now we calculate the actualDimmension
146 int actualDimmension = (int) (100 * factor);
147 int maxX = imageData.getWidth() - actualDimmension;
148 int maxY = imageData.getHeight() - actualDimmension;
150 int maxDiffX = Math.max(Math.abs(startPosX - maxX), startPosX);
151 int maxDiffY = Math.max(Math.abs(startPosY - maxY), startPosY);
154 TERMINATE: for ( float xDiff = 0.1f; Math.abs(xDiff) <= maxDiffX; xDiff =
155 (xDiff + sgn(xDiff) * 0.5f) * -1) {
165 int xPos = Math.round((float) (startPosX + xDiff));
167 if (xPos < 0 || xPos > maxX)
172 TERMINATE: for ( float yDiff = 0.1f; Math.abs(yDiff) <= maxDiffY; yDiff =
173 (yDiff + sgn(yDiff) * 0.5f) * -1) {
183 int yPos = Math.round(startPosY + yDiff);
184 if (yPos < 0 || yPos > maxY)
187 // by now we should have a valid coordinate to process which we should
189 boolean backToYLines = false;
190 for ( int idx = 0; idx < size; ++idx) {
191 float borderline = 0.8f + (idx / (size - 1)) * (maxBorder - 0.8f);
192 if (!classifiers[idx].classifyFace(imageData, factor, xPos, yPos, borderline)) {
199 // if we reach here we have a face recognized because our image went
207 x = xPos * originalImageFactor;
208 y = yPos * originalImageFactor;
209 width = actualDimmension * originalImageFactor;
210 height = actualDimmension * originalImageFactor;
224 private static int sgn( float value) {
225 return (value < 0 ? -1 : (value > 0 ? +1 : 1));
229 public FaceAndEyePosition getEyePosition( Image image) {
234 float originalImageFactor = 1;
236 locateFaceRadial(image);
238 if (width > image.getWidth() || height > image.getHeight()) {
242 EyePosition eyePosition = null;
245 EyeDetector ed = new EyeDetector(image, x, y, width, height);
246 Point point = ed.detectEye();
248 eyePosition = new EyePosition(point.getX(), point.getY());
252 System.out.println("eyePosition=" + eyePosition);
254 FaceAndEyePosition fep = new FaceAndEyePosition(x, y, width, height, eyePosition);