2 * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
4 * This file is part of LEA.
6 * LEA is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU Lesser General Public License as published by the Free
8 * Software Foundation, either version 3 of the License, or (at your option) any
11 * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with LEA. If not, see <http://www.gnu.org/licenses/>.
21 * This is the main class of LEA.
23 * It uses a face detection algorithm to find an a face within the provided
24 * image(s). Then it searches for the eye in a region where it most likely
25 * located and traces its position relative to the face and to the last known
26 * position. The movements are estimated by comparing more than one movement. If
27 * a movement is distinctly pointing to a direction it is recognized and all
28 * listeners get notified.
30 * The notification is designed as observer pattern. You simply call
31 * <code>addEyeMovementListener(IEyeMovementListener)</code> to add an
32 * implementation of <code>IEyeMovementListener</code> to LEA. When a face is
33 * recognized/lost or whenever an eye movement is detected LEA will call the
34 * appropriate methods of the listener
36 * LEA also needs an image source implementing the <code>ICaptureDevice</code>.
37 * One image source proxy to the <code>Java Media Framework</code> is included (
38 * <code>JMFCaptureDevice</code>).
40 * Example (for using LEA with <code>Java Media Framework</code>):
43 * LEA lea = new LEA(new JMFCaptureDevice(), true);
46 * This will start LEA with the first available JMF datasource with an extra
47 * status window showing if face/eye has been detected successfully. Please note
48 * that face detection needs about 2 seconds to find a face. After detection the
49 * following face detection is much faster.
51 * @author Florian Frankenberger
55 private boolean shutdown = false;
56 private LEAImplementation implementation;
58 private FaceAndEyePosition lastPositions = new FaceAndEyePosition(null, null);
59 private DeviationScanner deviationScanner = new DeviationScanner();
60 private int counter = 0;
62 // private ImageProcessor imageProcessor;
64 // private class ImageProcessor extends TimedThread {
66 // private FaceAndEyePosition lastPositions = new FaceAndEyePosition(null,
68 // private DeviationScanner deviationScanner = new DeviationScanner();
69 // private int counter = 0;
73 // public ImageProcessor(int fps) {
79 // public void doRun() {
81 // BufferedImage image = captureDevice.getImage();
86 // FaceAndEyePosition positions = implementation.getEyePosition(image);
88 // if (((lastPositions.getFacePosition() == null &&
89 // positions.getFacePosition() != null) || (lastPositions
90 // .getFacePosition() != null && positions.getFacePosition() == null)) ||
93 // if ((lastPositions.getFacePosition() == null && positions.getFacePosition()
95 // || (lastPositions.getFacePosition() != null && positions.getFacePosition()
97 // if (positions.getFacePosition() != null) {
98 // notifyEyeMovementListenerFaceDetected();
100 // notifyEyeMovementListenerFaceLost();
104 // if (statusWindow != null)
105 // statusWindow.getFaceInfoPanel().setFace(image,
106 // positions.getFacePosition());
109 // if (positions.getEyePosition() != null) {
110 // if (statusWindow != null) {
111 // statusWindow.getEyeInfoPanel().setEyePosition(image,
112 // positions.getFacePosition(),
113 // positions.getEyePosition());
115 // deviationScanner.addEyePosition(positions.getEyePosition());
116 // Deviation deviation =
117 // deviationScanner.scanForDeviation(positions.getFacePosition());//
118 // positions.getEyePosition().getDeviation(lastPositions.getEyePosition());
120 // if (deviation != Deviation.NONE) {
121 // notifyEyeMovementListenerEyeMoved(deviation);
125 // if (statusWindow != null)
126 // statusWindow.getEyeInfoPanel().setDeviation(null);
129 // lastPositions = positions;
130 // } catch (Exception e) {
131 // e.printStackTrace();
134 // } catch (Exception e2) {
139 // public synchronized void clearDeviationScanner() {
140 // this.deviationScanner.clear();
146 // this.imageProcessor = new
147 // ImageProcessor(this.captureDevice.getFrameRate());
148 implementation = new LEAImplementation();
152 * Clears the internal movement buffer. If you just capture some of the eye
153 * movements you should call this every time you start recording the
154 * movements. Otherwise you may get notified for movements that took place
155 * BEFORE you started recording.
157 public void clear() {
158 // this.imageProcessor.clearDeviationScanner();
162 * To test LEA with the first capture device from the
163 * <code>Java Media Framework</code> just start from here.
168 public static void main(String[] args) throws Exception {
173 public void doRun() {
178 ImageReader reader = new ImageReader();
180 while (i < maxCount) {
181 Image image = reader.readImage("data/e" + i + ".bmp");
189 System.out.println("Done.");
193 private void processImage(Image image) {
195 FaceAndEyePosition positions = implementation.getEyePosition(image);
197 if (positions.getEyePosition() != null) {
198 deviationScanner.addEyePosition(positions.getEyePosition());
199 Deviation deviation = deviationScanner.scanForDeviation(positions.getFacePosition());// positions.getEyePosition().getDeviation(lastPositions.getEyePosition());
200 // if (deviation != Deviation.NONE) {
201 // notifyEyeMovementListenerEyeMoved(deviation);
205 // if (statusWindow != null)
206 // statusWindow.getEyeInfoPanel().setDeviation(null);
208 lastPositions = positions;
209 // } catch (Exception e) {
210 // e.printStackTrace();
213 // } catch (Exception e2) {