add eye tracking benchmark.
authoryeom <yeom>
Wed, 14 Sep 2011 01:40:58 +0000 (01:40 +0000)
committeryeom <yeom>
Wed, 14 Sep 2011 01:40:58 +0000 (01:40 +0000)
get rid of all XML serialization.

24 files changed:
Robust/src/Benchmarks/SSJava/EyeTracking/Classifier.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/ClassifierTree.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/Deviation.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/DeviationScanner.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/Dimension.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/DummyCaptureDevice.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/EyeDetector.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/EyeInfoPanel.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/EyePosition.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/FaceAndEyePosition.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/FaceInfoPanel.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/ICaptureDevice.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/IEyeMovementListener.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/InfoPanel.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/IntegralImageData.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/JMFCaptureDevice.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/LEA.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/LEAImplementation.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/LEAStatusWindow.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/Point.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/ScanArea.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/StaticSizeArrayList.java [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/facedata.dat [new file with mode: 0644]
Robust/src/Benchmarks/SSJava/EyeTracking/makefile [new file with mode: 0644]

diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/Classifier.java b/Robust/src/Benchmarks/SSJava/EyeTracking/Classifier.java
new file mode 100644 (file)
index 0000000..1be3c78
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * 
+ * @author Florian
+ */
+public class Classifier {
+
+  private ScanArea[] scanAreas;
+
+  // private float possibilityFace = 0f;
+  private float[] possibilities_FaceYes;
+  private float[] possibilities_FaceNo;
+  private int possibilityFaceYes = 0;
+  private int possibilityFaceNo = 0;
+
+  public static final long serialVersionUID = 5168971806943656945l;
+
+  public Classifier(int numScanAreas) {
+    this.scanAreas = new ScanArea[numScanAreas];
+    this.possibilities_FaceYes = new float[numScanAreas];
+    this.possibilities_FaceNo = new float[numScanAreas];
+  }
+
+  public void setScanArea(int idx, ScanArea area) {
+    scanAreas[idx] = area;
+  }
+
+  public void setPossibilitiesFaceYes(float[] arr) {
+    this.possibilities_FaceYes = arr;
+  }
+
+  public void setPossibilityFaceYes(int v) {
+    this.possibilityFaceYes = v;
+  }
+
+  public void setPossibilitiesFaceNo(float[] arr) {
+    this.possibilities_FaceNo = arr;
+  }
+
+  public void setPossibilityFaceNo(int v) {
+    this.possibilityFaceNo = v;
+  }
+
+  // public void learn(IntegralImageData image, boolean isFace) {
+  // long values[] = new long[this.scanAreas.length];
+  // //
+  // System.out.println("HERE:"+image.getIntegralAt(image.getDimension().width-1,
+  // // image.getDimension().height-1));
+  // // we assume the image is rectangular so we can simply use one side to
+  // // calculate
+  // // the scale factor
+  // float scaleFactor = image.getDimension().width / 100.0f;
+  //
+  // float avg = 0f;
+  // int avgItems = 0;
+  // for (int i = 0; i < this.scanAreas.length; ++i) {
+  // ScanArea scanArea = this.scanAreas[i];
+  // values[i] = 0l;
+  //
+  // values[i] += image.getIntegralAt(scanArea.getToX(scaleFactor),
+  // scanArea.getToY(scaleFactor));
+  // values[i] +=
+  // image.getIntegralAt(scanArea.getFromX(scaleFactor),
+  // scanArea.getFromY(scaleFactor));
+  //
+  // values[i] -=
+  // image.getIntegralAt(scanArea.getToX(scaleFactor),
+  // scanArea.getFromY(scaleFactor));
+  // values[i] -=
+  // image.getIntegralAt(scanArea.getFromX(scaleFactor),
+  // scanArea.getToY(scaleFactor));
+  //
+  // values[i] = (long) (values[i] / ((float) scanArea.getSize(scaleFactor)));
+  // avg = ((avgItems * avg) + values[i]) / (++avgItems);
+  // }
+  //
+  // if (isFace) {
+  // this.possibilityFaceYes++;
+  // } else {
+  // this.possibilityFaceNo++;
+  // }
+  // for (int i = 0; i < this.scanAreas.length; ++i) {
+  // boolean bright = (values[i] >= avg);
+  //
+  // if (isFace) {
+  // // here we change the possibility of P(Scanarea_N = (Bright | NotBright)
+  // // | Face=Yes)
+  // this.possibilities_FaceYes[i] =
+  // (((this.possibilityFaceYes - 1) * this.possibilities_FaceYes[i]) + (bright
+  // ? 0.999f
+  // : 0.001f)) / this.possibilityFaceYes;
+  // //
+  // System.out.println("P(Scannarea"+i+"=bright|Face=Yes) = "+this.possibilities_FaceYes[i]);
+  // //
+  // System.out.println("P(Scannarea"+i+"=dark|Face=Yes) = "+(1.0f-this.possibilities_FaceYes[i]));
+  // } else {
+  // // here we change the possibility of P(Scanarea_N = (Bright | NotBright)
+  // // | Face=No)
+  // this.possibilities_FaceNo[i] =
+  // (((this.possibilityFaceNo - 1) * this.possibilities_FaceNo[i]) + (bright ?
+  // 0.999f
+  // : 0.001f)) / this.possibilityFaceNo;
+  // //
+  // System.out.println("P(Scannarea"+i+"=bright|Face=No) = "+this.possibilities_FaceNo[i]);
+  // //
+  // System.out.println("P(Scannarea"+i+"=dark|Face=No) = "+(1.0f-this.possibilities_FaceNo[i]));
+  // }
+  //
+  // }
+  //
+  // // System.out.println("Average: "+avg);
+  // // System.out.println(this);
+  // }
+
+  /**
+   * Classifies an images region as face
+   * 
+   * @param image
+   * @param scaleFactor
+   *          please be aware of the fact that the scanareas are scaled for use
+   *          with 100x100 px images
+   * @param translationX
+   * @param translationY
+   * @return true if this region was classified as face, else false
+   */
+  // public boolean classifyFace(IntegralImageData image, float scaleFactor, int
+  // translationX,
+  // int translationY, float borderline) {
+  //
+  // long values[] = new long[this.scanAreas.length];
+  //
+  // float avg = 0f;
+  // int avgItems = 0;
+  // for (int i = 0; i < this.scanAreas.length; ++i) {
+  // ScanArea scanArea = this.scanAreas[i];
+  // values[i] = 0l;
+  //
+  // values[i] +=
+  // image.getIntegralAt(translationX + scanArea.getToX(scaleFactor),
+  // translationY + scanArea.getToY(scaleFactor));
+  // values[i] +=
+  // image.getIntegralAt(translationX + scanArea.getFromX(scaleFactor),
+  // translationY
+  // + scanArea.getFromY(scaleFactor));
+  //
+  // values[i] -=
+  // image.getIntegralAt(translationX + scanArea.getToX(scaleFactor),
+  // translationY + scanArea.getFromY(scaleFactor));
+  // values[i] -=
+  // image.getIntegralAt(translationX + scanArea.getFromX(scaleFactor),
+  // translationY
+  // + scanArea.getToY(scaleFactor));
+  //
+  // values[i] = (long) (values[i] / ((float) scanArea.getSize(scaleFactor)));
+  // avg = ((avgItems * avg) + values[i]) / (++avgItems);
+  // }
+  //
+  // // int amountYesNo = this.possibilityFaceNo + this.possibilityFaceYes;
+  //
+  // // calculate the possibilites for face=yes and face=no with naive bayes
+  // // P(Yes | M1 and ... and Mn) = P(Yes) * P(M1 | Yes) * ... * P(Mn | Yes)
+  // /xx
+  // // P(No | M1 and ... and Mn) = P(No) * P(M1 | No) * ... * P(Mn | No) / xx
+  // // as we just maximize the args we don't actually calculate the accurate
+  // // possibility
+  //
+  // float isFaceYes = 1.0f;// this.possibilityFaceYes / (float)amountYesNo;
+  // float isFaceNo = 1.0f;// this.possibilityFaceNo / (float)amountYesNo;
+  //
+  // for (int i = 0; i < this.scanAreas.length; ++i) {
+  // boolean bright = (values[i] >= avg);
+  // isFaceYes *= (bright ? this.possibilities_FaceYes[i] : 1 -
+  // this.possibilities_FaceYes[i]);
+  // isFaceNo *= (bright ? this.possibilities_FaceNo[i] : 1 -
+  // this.possibilities_FaceNo[i]);
+  // }
+  //
+  // return (isFaceYes >= isFaceNo && (isFaceYes / (isFaceYes + isFaceNo)) >
+  // borderline);
+  // }
+
+  public ScanArea[] getScanAreas() {
+    return this.scanAreas;
+  }
+
+  public int getLearnedFacesYes() {
+    return this.possibilityFaceYes;
+  }
+
+  public int getLearnedFacesNo() {
+    return this.possibilityFaceNo;
+  }
+
+  public float getPossibility(int scanAreaID, boolean faceYes, boolean bright) {
+    if (faceYes) {
+      return (bright ? this.possibilities_FaceYes[scanAreaID]
+          : 1 - this.possibilities_FaceYes[scanAreaID]);
+    } else {
+      return (bright ? this.possibilities_FaceNo[scanAreaID]
+          : 1 - this.possibilities_FaceNo[scanAreaID]);
+    }
+  }
+
+  public int compareTo(Classifier o) {
+    if (o.getScanAreas().length > this.getScanAreas().length) {
+      return -1;
+    } else if (o.getScanAreas().length < this.getScanAreas().length) {
+      return 1;
+    } else
+      return 0;
+  }
+
+  public String toString() {
+
+    String str = "";
+    for (int i = 0; i < scanAreas.length; i++) {
+      str += scanAreas[i].toString() + "\n";
+    }
+
+    return str;
+
+  }
+  // @Override
+  // public String toString() {
+  // StringBuilder sb = new StringBuilder();
+  // sb.append("Classifier [ScanAreas: " + this.scanAreas.length);
+  // int yesNo = this.possibilityFaceYes + this.possibilityFaceNo;
+  // sb.append(String.format("|Yes: %3.2f| No:%3.2f] (",
+  // (this.possibilityFaceYes / (float) yesNo) * 100.0f,
+  // (this.possibilityFaceNo / (float) yesNo) * 100.0f));
+  // for (int i = 0; i < this.scanAreas.length; ++i) {
+  // sb.append(String.format("[%3d|Yes: %3.2f| No: %3.2f], ", i + 1,
+  // (this.possibilities_FaceYes[i] * 100.0f), (this.possibilities_FaceNo[i] *
+  // 100.0f)));
+  // }
+  // sb.append(")");
+  //
+  // return sb.toString();
+  // }
+
+  /**
+   * Generates a new set of classifiers each with more ScanAreas than the last
+   * classifier. You can specifiy the amount of classifiers you want to generate
+   * 
+   * @param amount
+   *          amount of classifiers to create
+   * @param startAmountScanAreas
+   *          the start amount of scanAreas - if your first classifiers should
+   *          contain 3 items you should give 3 here
+   * @param incAmountScanAreas
+   *          the amount of which the scanAreas should increase - a simple 2
+   *          will increase them by 2 every step
+   * @return a List of classifiers
+   */
+  // public static List<Classifier> generateNewClassifiers(int amount, int
+  // startAmountScanAreas,
+  // float incAmountScanAreas) {
+  // List<Classifier> classifiers = new ArrayList<Classifier>();
+  //
+  // int maxDim = 40;
+  // Random random = new Random(System.currentTimeMillis());
+  // double maxSpace = 2 * Math.PI * Math.pow(50, 2);
+  //
+  // for (int i = 0; i < amount; ++i) {
+  // // we create an odd amount of ScanAreas starting with 1 (3, 5, 7, ...)
+  // int scanAreaAmount = startAmountScanAreas + (int)
+  // Math.pow(incAmountScanAreas, i);// +
+  // // ((i)*incAmountScanAreas+1);
+  //
+  // int scanAreaSize =
+  // randomInt(random, scanAreaAmount * 20, (int) Math.min(maxDim * maxDim,
+  // maxSpace))
+  // / scanAreaAmount;
+  // // System.out.println("scanAreaSize = "+scanAreaSize);
+  //
+  // List<ScanArea> scanAreas = new ArrayList<ScanArea>();
+  //
+  // for (int j = 0; j < scanAreaAmount; ++j) {
+  //
+  // int counter = 0;
+  // ScanArea scanArea = null;
+  // do {
+  // // new the width has the first choice
+  // int minWidth = (int) Math.ceil(scanAreaSize / (float) maxDim);
+  //
+  // int scanAreaWidth = randomInt(random, minWidth, Math.min(maxDim,
+  // scanAreaSize / 2));
+  // int scanAreaHeight = (int) Math.ceil(scanAreaSize / (float) scanAreaWidth);
+  //
+  // int radius =
+  // randomInt(random, 5, Math.min(50 - scanAreaHeight / 2, 50 - scanAreaWidth /
+  // 2));
+  // double angle = random.nextFloat() * 2 * Math.PI;
+  //
+  // int posX = (int) (50 + Math.cos(angle) * radius) - (scanAreaWidth / 2);
+  // int posY = (int) (50 + Math.sin(angle) * radius) - (scanAreaHeight / 2);
+  //
+  // // System.out.println("[Angle: "+(angle /
+  // // (Math.PI*2)*180)+" | radius: "+radius+"]");
+  // //
+  // System.out.println("Area"+j+" is "+posX+", "+posY+" ("+scanAreaWidth+" x "+scanAreaHeight+" = "+((scanAreaWidth*scanAreaHeight))+")");
+  //
+  // // now we get random position for this area
+  // scanArea = new ScanArea(posX, posY, scanAreaWidth, scanAreaHeight);
+  //
+  // counter++;
+  // } while (scanAreas.contains(scanArea) && counter < 30);
+  //
+  // if (counter == 30) {
+  // j -= 1;
+  // continue;
+  // }
+  //
+  // scanAreas.add(scanArea);
+  // }
+  //
+  // Classifier classifier = new Classifier(scanAreas.toArray(new ScanArea[0]));
+  // classifiers.add(classifier);
+  // }
+  //
+  // return classifiers;
+  // }
+
+  // private static int randomInt(Random random, int from, int to) {
+  // if (to - from <= 0)
+  // to = from + 1;
+  // return from + random.nextInt(to - from);
+  // }
+  //
+  // public static List<Classifier> getDefaultClassifier() {
+  // List<Classifier> classifier = new ArrayList<Classifier>();
+  //
+  // classifier.add(new Classifier(new ScanArea(30, 30, 30, 30), new
+  // ScanArea(15, 8, 15, 82),
+  // new ScanArea(75, 8, 15, 82)));
+  //
+  // return classifier;
+  // }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/ClassifierTree.java b/Robust/src/Benchmarks/SSJava/EyeTracking/ClassifierTree.java
new file mode 100644 (file)
index 0000000..4c66aff
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ColorConvertOp;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 
+ * @author Florian
+ */
+public class ClassifierTree {
+
+  private List<Classifier> classifiers;
+  private static XStream xStream = new XStream(new DomDriver());
+
+  static {
+    xStream.alias("ClassifierTree", ClassifierTree.class);
+    xStream.alias("Classifier", Classifier.class);
+    xStream.alias("ScanArea", ScanArea.class);
+  }
+
+  public ClassifierTree(List<Classifier> classifier) {
+    this.classifiers = new ArrayList<Classifier>(classifier);
+    Collections.sort(this.classifiers);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("ClassifierTree {\n");
+    for (Classifier classifier : this.classifiers) {
+      sb.append(classifier.toString());
+      sb.append('\n');
+    }
+    sb.append("}\n");
+    return sb.toString();
+  }
+
+  public static BufferedImage resizeImageFittingInto(BufferedImage image, int dimension) {
+
+    int newHeight = 0;
+    int newWidth = 0;
+    float factor = 0;
+    if (image.getWidth() > image.getHeight()) {
+      factor = dimension / (float) image.getWidth();
+      newWidth = dimension;
+      newHeight = (int) (factor * image.getHeight());
+    } else {
+      factor = dimension / (float) image.getHeight();
+      newHeight = dimension;
+      newWidth = (int) (factor * image.getWidth());
+    }
+
+    if (factor > 1) {
+      BufferedImageOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
+      BufferedImage tmpImage = op.filter(image, null);
+
+      return tmpImage;
+    }
+
+    BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
+
+    Graphics2D g2D = resizedImage.createGraphics();
+    g2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+        RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+
+    g2D.drawImage(image, 0, 0, newWidth - 1, newHeight - 1, 0, 0, image.getWidth() - 1,
+        image.getHeight() - 1, null);
+
+    BufferedImageOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
+    BufferedImage tmpImage = op.filter(resizedImage, null);
+
+    return tmpImage;
+  }
+
+  /**
+   * Image should have 100x100px and should be in b/w
+   * 
+   * @param image
+   */
+  public void learn(BufferedImage image, boolean isFace) {
+    IntegralImageData imageData = new IntegralImageData(image);
+    for (Classifier classifier : this.classifiers) {
+      classifier.learn(imageData, isFace);
+    }
+  }
+
+  public int getLearnedFacesYes() {
+    return this.classifiers.get(0).getLearnedFacesYes();
+  }
+
+  public int getLearnedFacesNo() {
+    return this.classifiers.get(0).getLearnedFacesNo();
+  }
+
+  /**
+   * Locates a face by linear iteration through all probable face positions
+   * 
+   * @deprecated use locateFaceRadial instead for improved performance
+   * @param image
+   * @return an rectangle representing the actual face position on success or
+   *         null if no face could be detected
+   */
+  public Rectangle2D locateFace(BufferedImage image) {
+    long timeStart = System.currentTimeMillis();
+
+    int resizeTo = 600;
+
+    BufferedImage smallImage = resizeImageFittingInto(image, resizeTo);
+    IntegralImageData imageData = new IntegralImageData(smallImage);
+
+    float factor = image.getWidth() / (float) smallImage.getWidth();
+
+    int maxIterations = 0;
+
+    // first we calculate the maximum scale factor for our 200x200 image
+    float maxScaleFactor = Math.min(imageData.getWidth() / 100f, imageData.getHeight() / 100f);
+
+    // we simply won't recognize faces that are smaller than 40x40 px
+    float minScaleFactor = 0.5f;
+
+    // border for faceYes-possibility must be greater that that
+    float maxBorder = 0.999f;
+
+    for (float scale = maxScaleFactor; scale > minScaleFactor; scale -= 0.25) {
+      int actualDimension = (int) (scale * 100);
+      int borderX = imageData.getWidth() - actualDimension;
+      int borderY = imageData.getHeight() - actualDimension;
+      for (int x = 0; x <= borderX; ++x) {
+        yLines: for (int y = 0; y <= borderY; ++y) {
+
+          for (int iterations = 0; iterations < this.classifiers.size(); ++iterations) {
+            Classifier classifier = this.classifiers.get(iterations);
+
+            float borderline =
+                0.8f + (iterations / this.classifiers.size() - 1) * (maxBorder - 0.8f);
+            if (iterations > maxIterations)
+              maxIterations = iterations;
+            if (!classifier.classifyFace(imageData, scale, x, y, borderline)) {
+              continue yLines;
+            }
+          }
+
+          // if we reach here we have a face recognized because our image went
+          // through all
+          // classifiers
+
+          Rectangle2D faceRect =
+              new Rectangle2D.Float(x * factor, y * factor, actualDimension * factor,
+                  actualDimension * factor);
+
+          System.out.println("Time: " + (System.currentTimeMillis() - timeStart) + "ms");
+          return faceRect;
+
+        }
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Locates a face by searching radial starting at the last known position. If
+   * lastCoordinates are null we simply start in the center of the image.
+   * <p>
+   * TODO: This method could quite possible be tweaked so that face recognition
+   * would be much faster
+   * 
+   * @param image
+   *          the image to process
+   * @param lastCoordinates
+   *          the last known coordinates or null if unknown
+   * @return an rectangle representing the actual face position on success or
+   *         null if no face could be detected
+   */
+  public Rectangle2D locateFaceRadial(BufferedImage image, Rectangle2D lastCoordinates) {
+
+    int resizeTo = 600;
+
+    BufferedImage smallImage = resizeImageFittingInto(image, resizeTo);
+    float originalImageFactor = image.getWidth() / (float) smallImage.getWidth();
+    IntegralImageData imageData = new IntegralImageData(smallImage);
+
+    if (lastCoordinates == null) {
+      // if we don't have a last coordinate we just begin in the center
+      int smallImageMaxDimension = Math.min(smallImage.getWidth(), smallImage.getHeight());
+      lastCoordinates =
+          new Rectangle2D.Float((smallImage.getWidth() - smallImageMaxDimension) / 2.0f,
+              (smallImage.getHeight() - smallImageMaxDimension) / 2.0f, smallImageMaxDimension,
+              smallImageMaxDimension);
+    } else {
+      // first we have to scale the last coodinates back relative to the resized
+      // image
+      lastCoordinates =
+          new Rectangle2D.Float((float) (lastCoordinates.getX() * (1 / originalImageFactor)),
+              (float) (lastCoordinates.getY() * (1 / originalImageFactor)),
+              (float) (lastCoordinates.getWidth() * (1 / originalImageFactor)),
+              (float) (lastCoordinates.getHeight() * (1 / originalImageFactor)));
+    }
+
+    float startFactor = (float) (lastCoordinates.getWidth() / 100.0f);
+
+    // first we calculate the maximum scale factor for our 200x200 image
+    float maxScaleFactor = Math.min(imageData.getWidth() / 100f, imageData.getHeight() / 100f);
+    // maxScaleFactor = 1.0f;
+
+    // we simply won't recognize faces that are smaller than 40x40 px
+    float minScaleFactor = 0.5f;
+
+    float maxScaleDifference =
+        Math.max(Math.abs(maxScaleFactor - startFactor), Math.abs(minScaleFactor - startFactor));
+
+    // border for faceYes-possibility must be greater that that
+    float maxBorder = 0.999f;
+
+    int startPosX = (int) lastCoordinates.getX();
+    int startPosY = (int) lastCoordinates.getX();
+
+    for (float factorDiff = 0.0f; Math.abs(factorDiff) <= maxScaleDifference; factorDiff =
+        (factorDiff + sgn(factorDiff) * 0.1f) * -1 // we alternate between
+                                                   // negative and positiv
+                                                   // factors
+    ) {
+
+      float factor = startFactor + factorDiff;
+      if (factor > maxScaleFactor || factor < minScaleFactor)
+        continue;
+
+      // now we calculate the actualDimmension
+      int actualDimmension = (int) (100 * factor);
+      int maxX = imageData.getWidth() - actualDimmension;
+      int maxY = imageData.getHeight() - actualDimmension;
+
+      int maxDiffX = Math.max(Math.abs(startPosX - maxX), startPosX);
+      int maxDiffY = Math.max(Math.abs(startPosY - maxY), startPosY);
+
+      for (float xDiff = 0.1f; Math.abs(xDiff) <= maxDiffX; xDiff =
+          (xDiff + sgn(xDiff) * 0.5f) * -1) {
+        int xPos = Math.round(startPosX + xDiff);
+        if (xPos < 0 || xPos > maxX)
+          continue;
+
+        yLines: for (float yDiff = 0.1f; Math.abs(yDiff) <= maxDiffY; yDiff =
+            (yDiff + sgn(yDiff) * 0.5f) * -1) {
+          int yPos = Math.round(startPosY + yDiff);
+          if (yPos < 0 || yPos > maxY)
+            continue;
+
+          // by now we should have a valid coordinate to process which we should
+          // do now
+          for (int iterations = 0; iterations < this.classifiers.size(); ++iterations) {
+            Classifier classifier = this.classifiers.get(iterations);
+
+            float borderline =
+                0.8f + (iterations / (this.classifiers.size() - 1)) * (maxBorder - 0.8f);
+
+            if (!classifier.classifyFace(imageData, factor, xPos, yPos, borderline)) {
+              continue yLines;
+            }
+          }
+
+          // if we reach here we have a face recognized because our image went
+          // through all
+          // classifiers
+
+          Rectangle2D faceRect =
+              new Rectangle2D.Float(xPos * originalImageFactor, yPos * originalImageFactor,
+                  actualDimmension * originalImageFactor, actualDimmension * originalImageFactor);
+
+          return faceRect;
+
+        }
+
+      }
+
+    }
+
+    // System.out.println("Time: "+(System.currentTimeMillis()-timeStart)+"ms");
+    return null;
+
+  }
+
+  public List<Classifier> getClassifiers() {
+    return new ArrayList<Classifier>(this.classifiers);
+  }
+
+  public static void saveToXml(OutputStream out, ClassifierTree tree) throws IOException {
+    PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
+    writer.write(xStream.toXML(tree));
+    writer.close();
+  }
+
+  public static ClassifierTree loadFromXml(InputStream in) throws IOException {
+    Reader reader = new InputStreamReader(in, "UTF-8");
+    StringBuilder sb = new StringBuilder();
+
+    char[] buffer = new char[1024];
+    int read = 0;
+    do {
+      read = reader.read(buffer);
+      if (read > 0) {
+        sb.append(buffer, 0, read);
+      }
+    } while (read > -1);
+    reader.close();
+
+    return (ClassifierTree) xStream.fromXML(sb.toString());
+  }
+
+  private static int sgn(float value) {
+    return (value < 0 ? -1 : (value > 0 ? +1 : 1));
+  }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/Deviation.java b/Robust/src/Benchmarks/SSJava/EyeTracking/Deviation.java
new file mode 100644 (file)
index 0000000..bc76ef7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ * Representing an eyes deviation
+ * 
+ * @author Florian Frankenberger
+ */
+public enum Deviation {
+        LEFT_UP(+1, -1),
+        UP(0, -1),
+        RIGHT_UP(-1, -1),
+        LEFT(+1, 0),
+        NONE(0, 0),
+        RIGHT(-1, 0),
+        LEFT_DOWN(+1, +1),
+        DOWN(0, +1),
+        RIGHT_DOWN(-1, +1);
+
+        int directionX, directionY;
+        Deviation(int directionX, int directionY) {
+            this.directionX = directionX;
+            this.directionY = directionY;
+        }
+
+        private boolean concurs(int directionX, int directionY) {
+            return (directionX == this.directionX && directionY == this.directionY);
+        }
+
+
+        public static Deviation getDirectionFor(int directionX, int directionY) {
+            for (Deviation direction: Deviation.values()) {
+                if (direction.concurs(directionX, directionY)) {
+                    return direction;
+                }
+            }
+
+            return null;
+        }
+  }
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/DeviationScanner.java b/Robust/src/Benchmarks/SSJava/EyeTracking/DeviationScanner.java
new file mode 100644 (file)
index 0000000..aa09a48
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)\r
+ * \r
+ * This file is part of LEA.\r
+ * \r
+ * LEA is free software: you can redistribute it and/or modify it under the\r
+ * terms of the GNU Lesser General Public License as published by the Free\r
+ * Software Foundation, either version 3 of the License, or (at your option) any\r
+ * later version.\r
+ * \r
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more\r
+ * details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+\r
+\r
+import java.awt.geom.Rectangle2D;\r
+\r
+/**\r
+ * No description given.\r
+ * \r
+ * @author Florian Frankenberger\r
+ */\r
+public class DeviationScanner {\r
+\r
+       private StaticSizeArrayList<EyePosition> eyePositions = new StaticSizeArrayList<EyePosition>(3);\r
+       \r
+       public DeviationScanner() {\r
+       }\r
+\r
+       public void addEyePosition(EyePosition eyePosition) {\r
+               eyePositions.add(eyePosition);\r
+       }\r
+       \r
+       public Deviation scanForDeviation(Rectangle2D faceRect) {\r
+               Deviation deviation = Deviation.NONE;\r
+               if (eyePositions.size() >= 3) {\r
+                       double deviationX = 0;\r
+                       double deviationY = 0;\r
+                       \r
+                       EyePosition lastEyePosition = null;\r
+                       for (int i = 0; i < 3; ++i) {\r
+                               EyePosition eyePosition = this.eyePositions.get(i);\r
+                               if (lastEyePosition != null) {\r
+                                       deviationX += (eyePosition.getX() - lastEyePosition.getX());\r
+                                       deviationY += (eyePosition.getY() - lastEyePosition.getY());\r
+                               }\r
+                               lastEyePosition = eyePosition; \r
+                       }\r
+                       \r
+                       final double deviationPercentX = 0.04;\r
+                       final double deviationPercentY = 0.04;\r
+                       \r
+                       deviationX /= faceRect.getWidth();\r
+                       deviationY /= faceRect.getWidth();\r
+                       \r
+                       int deviationAbsoluteX = 0;\r
+                       int deviationAbsoluteY = 0;\r
+                       if (deviationX > deviationPercentX) deviationAbsoluteX = 1;\r
+                       if (deviationX < -deviationPercentX) deviationAbsoluteX = -1;\r
+                       if (deviationY > deviationPercentY) deviationAbsoluteY = 1;\r
+                       if (deviationY < -deviationPercentY) deviationAbsoluteY = -1;\r
+                       \r
+                       deviation = Deviation.getDirectionFor(deviationAbsoluteX, deviationAbsoluteY);\r
+                       if (deviation != Deviation.NONE) this.eyePositions.clear();\r
+                       //System.out.println(String.format("%.2f%% | %.2f%% => %d and %d >>> %s", deviationX*100, deviationY*100, deviationAbsoluteX, deviationAbsoluteY, deviation.toString()));\r
+                       \r
+               }\r
+               \r
+               return deviation;\r
+       }\r
+       \r
+       public void clear() {\r
+               System.out.println("CLEAR");\r
+               this.eyePositions.clear();\r
+       }\r
+}\r
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/Dimension.java b/Robust/src/Benchmarks/SSJava/EyeTracking/Dimension.java
new file mode 100644 (file)
index 0000000..c6013eb
--- /dev/null
@@ -0,0 +1,5 @@
+public class Dimension {
+  public int width;
+  public int height;
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/DummyCaptureDevice.java b/Robust/src/Benchmarks/SSJava/EyeTracking/DummyCaptureDevice.java
new file mode 100644 (file)
index 0000000..699a620
--- /dev/null
@@ -0,0 +1,52 @@
+/**\r
+ * \r
+ */\r
+\r
+import java.awt.Color;\r
+import java.awt.Graphics2D;\r
+import java.awt.image.BufferedImage;\r
+\r
+import de.darkblue.lea.ifaces.ICaptureDevice;\r
+\r
+/**\r
+ * No description given.\r
+ * \r
+ * @author Florian Frankenberger\r
+ */\r
+public class DummyCaptureDevice implements ICaptureDevice {\r
+\r
+       /**\r
+        * \r
+        */\r
+       public DummyCaptureDevice() {\r
+               // TODO Auto-generated constructor stub\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see de.darkblue.lea.ifaces.ICaptureDevice#close()\r
+        */\r
+       @Override\r
+       public void close() {\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see de.darkblue.lea.ifaces.ICaptureDevice#getFrameRate()\r
+        */\r
+       @Override\r
+       public int getFrameRate() {\r
+               return 15;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see de.darkblue.lea.ifaces.ICaptureDevice#getImage()\r
+        */\r
+       @Override\r
+       public BufferedImage getImage() {\r
+               BufferedImage image = new BufferedImage(640, 480, BufferedImage.TYPE_INT_RGB);\r
+               Graphics2D g2d = (Graphics2D)image.getGraphics();\r
+               g2d.setColor(new Color(255, 255, 255));\r
+               g2d.fillRect(0, 0, 639, 479);\r
+               return image;\r
+       }\r
+\r
+}\r
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/EyeDetector.java b/Robust/src/Benchmarks/SSJava/EyeTracking/EyeDetector.java
new file mode 100644 (file)
index 0000000..0cc7144
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+import java.awt.Point;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.PixelGrabber;
+
+/**
+ * No description given.
+ * 
+ * @author Florian Frankenberger
+ */
+class EyeDetector {
+
+    private int width;
+    private int height;
+    private int[] pixelBuffer;
+
+    double percent;
+
+    public EyeDetector(BufferedImage image, Rectangle2D faceRect) {
+
+        percent = 0.15*faceRect.getWidth();
+        faceRect = new Rectangle2D.Double(
+                    faceRect.getX()+ percent,
+                    faceRect.getY()+ percent,
+                    faceRect.getWidth() - percent,
+                    faceRect.getHeight() - 2*percent
+                );
+        
+        width = (int)faceRect.getWidth() / 2;
+        height = (int)faceRect.getHeight() / 2;
+        pixelBuffer = new int[width*height];
+        PixelGrabber pg = new PixelGrabber(
+                image,
+                (int)faceRect.getX(), (int)faceRect.getY(),
+                width, height,
+                pixelBuffer, 0, width);
+
+        try {
+            pg.grabPixels();
+        } catch (InterruptedException ie) {}
+    }
+
+    public Point detectEye() {
+        Point eyePosition = null;
+        float brightness = 255f;
+
+        for (int y = 0; y < height; ++y) {
+            for (int x = 0; x < width; ++x) {
+                final int position = y*width + x;
+                final int[] color = new int[] { (pixelBuffer[position] & 0xFF0000) >> 16, (pixelBuffer[position] & 0x00FF00) >> 8, pixelBuffer[position] & 0x0000FF };
+                final float acBrightness = getBrightness(color);
+
+                if (acBrightness < brightness) {
+                    eyePosition = new Point(x + (int)percent,  y + (int)percent);
+                    brightness = acBrightness;
+                }
+            }
+        }
+
+        return eyePosition;
+    }
+
+    private static float getBrightness(int[] color) {
+        int min = Math.min(Math.min(color[0], color[1]), color[2]);
+        int max = Math.max(Math.max(color[0], color[1]), color[2]);
+
+        return 0.5f * (max + min);
+    }
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/EyeInfoPanel.java b/Robust/src/Benchmarks/SSJava/EyeTracking/EyeInfoPanel.java
new file mode 100644 (file)
index 0000000..544a48d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * 
+ * @author Florian
+ */
+class EyeInfoPanel extends InfoPanel {
+
+  private static final long serialVersionUID = 7681992432092759058L;
+
+  public EyeInfoPanel() {
+    super("Eye Status", new String[] { "nolock.png" }, 0, 100, 40);
+  }
+
+  public void setDeviation(Deviation deviation) {
+    if (deviation == null) {
+      this.setImage(null);
+    } else {
+      this.setImage(loadImage(deviation.toString() + ".png"));
+    }
+  }
+
+  public void setEyePosition(BufferedImage image, Rectangle2D faceRect, EyePosition eyePosition) {
+
+    BufferedImage faceRectImage = null;
+    if (image != null && faceRect != null) {
+      int width = 100;
+      int height = 40;
+
+      int posX = (int) (faceRect.getX() + eyePosition.getX());
+      int posY = (int) (faceRect.getY() + eyePosition.getY());
+
+      int targetWidth = (int) (0.3 * faceRect.getWidth());
+      int targetHeight = (int) (height / (float) width * targetWidth);
+
+      faceRectImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+
+      Graphics2D g2D = faceRectImage.createGraphics();
+      g2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+          RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+
+      g2D.drawImage(image, 0, 0, width, height, posX - targetWidth / 2, posY - targetHeight / 2,
+          posX + targetWidth / 2, posY + targetHeight / 2, null);
+
+    }
+    this.setImage(faceRectImage);
+  }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/EyePosition.java b/Robust/src/Benchmarks/SSJava/EyeTracking/EyePosition.java
new file mode 100644 (file)
index 0000000..11aef4c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.darkblue.lea.model;
+
+import java.awt.Point;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * No description given.
+ * 
+ * @author Florian Frankenberger
+ */
+public class EyePosition {
+    private int x;
+    private int y;
+    private Rectangle2D faceRect;
+
+    public EyePosition(Point p, Rectangle2D faceRect) {
+        this(p.x, p.y, faceRect);
+    }
+    
+    public EyePosition(int x, int y, Rectangle2D faceRect) {
+        this.x = x;
+        this.y = y;
+        this.faceRect = faceRect;
+    }
+
+    public int getX() {
+        return this.x;
+    }
+
+    public int getY() {
+        return this.y;
+    }
+    
+    public Deviation getDeviation(EyePosition oldEyePosition) {
+        if (oldEyePosition == null) return Deviation.NONE;
+
+        //first we check if the faceRects are corresponding
+        double widthChange = (this.faceRect.getWidth() - oldEyePosition.faceRect.getWidth()) / this.faceRect.getWidth();
+        if (widthChange > 0.1) return Deviation.NONE;
+
+        int maxDeviationX = (int)Math.round(this.faceRect.getWidth() / 4f);
+        int maxDeviationY = (int)Math.round(this.faceRect.getWidth() / 8f);
+        int minDeviation = (int)Math.round(this.faceRect.getWidth() / 16f);
+
+        int deviationX = Math.abs(x - oldEyePosition.x);
+        int directionX = sgn(x - oldEyePosition.x);
+        if (deviationX < minDeviation || deviationX > maxDeviationX) directionX = 0;
+
+        int deviationY = Math.abs(y - oldEyePosition.y);
+        int directionY = sgn(y - oldEyePosition.y);
+        if (deviationY < minDeviation || deviationY > maxDeviationY) directionY = 0;
+
+        double deviationXPercent = deviationX / this.faceRect.getWidth();
+        double deviationYPercent = deviationY / this.faceRect.getWidth();
+        
+        System.out.println(String.format("devX: %.2f | devY: %.2f", deviationXPercent*100f, deviationYPercent*100f));
+        return Deviation.getDirectionFor(directionX, directionY);
+    }
+
+
+    private static int sgn(int i) {
+        if (i > 0) return 1;
+        if (i < 0) return -1;
+        return 0;
+    }
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/FaceAndEyePosition.java b/Robust/src/Benchmarks/SSJava/EyeTracking/FaceAndEyePosition.java
new file mode 100644 (file)
index 0000000..97d9801
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.darkblue.lea.model;
+
+import java.awt.geom.Rectangle2D;
+
+/**
+ * No description given.
+ * 
+ * @author Florian Frankenberger
+ */
+public class FaceAndEyePosition {
+
+    private Rectangle2D facePosition;
+    private EyePosition eyePosition;
+
+    public FaceAndEyePosition(Rectangle2D facePosition, EyePosition eyePosition) {
+        this.facePosition = facePosition;
+        this.eyePosition = eyePosition;
+    }
+
+    public Rectangle2D getFacePosition() {
+        return this.facePosition;
+    }
+
+    public EyePosition getEyePosition() {
+        return this.eyePosition;
+    }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/FaceInfoPanel.java b/Robust/src/Benchmarks/SSJava/EyeTracking/FaceInfoPanel.java
new file mode 100644 (file)
index 0000000..a696ece
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @author Florian
+ */
+class FaceInfoPanel extends InfoPanel {
+
+       private static final long serialVersionUID = 453216951714787407L;
+
+       public FaceInfoPanel() {
+        super(
+                "Face Detection",
+                new String[] {
+                    "noface0.png",
+                    "noface1.png"
+                },
+                2,
+                100,
+                100);
+        this.setFace(null, null);
+    }
+
+    public void setFace(BufferedImage image, Rectangle2D faceRect) {
+
+        BufferedImage faceRectImage = null;
+        if (image != null && faceRect != null) {
+            int width = (int)faceRect.getWidth();
+            int height = (int)faceRect.getHeight();
+
+            faceRectImage = new BufferedImage(width,
+                      height, BufferedImage.TYPE_INT_RGB);
+
+            Graphics2D g2D = faceRectImage.createGraphics();
+            g2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                        RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+
+            g2D.drawImage(image, 0, 0, width, height, (int)faceRect.getX(), (int)faceRect.getY(), (int)faceRect.getX() + width, (int)faceRect.getY() + height, null);
+
+        }
+        this.setImage(faceRectImage);
+    }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/ICaptureDevice.java b/Robust/src/Benchmarks/SSJava/EyeTracking/ICaptureDevice.java
new file mode 100644 (file)
index 0000000..f050a97
--- /dev/null
@@ -0,0 +1,52 @@
+/*\r
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)\r
+ * \r
+ * This file is part of LEA.\r
+ * \r
+ * LEA is free software: you can redistribute it and/or modify it under the\r
+ * terms of the GNU Lesser General Public License as published by the Free\r
+ * Software Foundation, either version 3 of the License, or (at your option) any\r
+ * later version.\r
+ * \r
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more\r
+ * details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+\r
+\r
+import java.awt.image.BufferedImage;\r
+\r
+/**\r
+ * Describes a capture device. For now it is only tested\r
+ * with images in <code>640x480</code> at <code>RGB</code> or <code>YUV</code> color space.\r
+ * \r
+ * @author Florian Frankenberger\r
+ */\r
+public interface ICaptureDevice {\r
+\r
+       /**\r
+        * Returns the frame rate of the image source per second\r
+        * \r
+        * @return the frame rate (e.g. 15 = 15 frames per second)\r
+        */\r
+       public int getFrameRate();\r
+\r
+       /**\r
+        * Will be called a maximum of getFrameRate()-times in a second and returns\r
+        * the actual image of the capture device\r
+        *  \r
+        * @return the actual image of the capture device \r
+        */\r
+       public BufferedImage getImage();\r
+       \r
+       /**\r
+        * LEA calls this when it cleans up. You should put your own cleanup code in here.\r
+        */\r
+       public void close();\r
+       \r
+       \r
+}\r
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/IEyeMovementListener.java b/Robust/src/Benchmarks/SSJava/EyeTracking/IEyeMovementListener.java
new file mode 100644 (file)
index 0000000..339514c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+import de.darkblue.lea.model.Deviation;
+
+/**
+ * Implementations of eye movements and face detections should
+ * look like this.
+ * s
+ * @author Florian Frankenberger
+ */
+public interface IEyeMovementListener {
+
+       /**
+        * Is called whenever a face has been detected. Only
+        * if a face was detected <code>onEyeMoved</code> will be
+        * called (no face = no eye movement)
+        */
+    public void onFaceDetected();
+    
+    /**
+     * If the face was lost this method is being called
+     */
+    public void onFaceLost();
+
+    /**
+     * Gets called whenever an eye movement has been recognized
+     * 
+     * @param deviation the calculated deviation
+     */
+    public void onEyeMoved(Deviation deviation);
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/InfoPanel.java b/Robust/src/Benchmarks/SSJava/EyeTracking/InfoPanel.java
new file mode 100644 (file)
index 0000000..77bf54f
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.imageio.ImageIO;
+import javax.swing.JPanel;
+
+/**
+ *
+ * @author Florian
+ */
+abstract class InfoPanel extends JPanel {
+
+       private static final long serialVersionUID = 8311083210432152308L;
+       
+       private String text = "";
+    private BufferedImage image = null;
+    private BufferedImage[] noImageImages = null;
+    private int imageWidth, imageHeight;
+    private int animationTime = 0;
+
+    private AnimationThread animationThread = null;
+
+    private class AnimationThread extends Thread {
+
+        private boolean shutdown = false;
+        private int counter = 0;
+
+        public AnimationThread() {
+            this.start();
+        }
+
+        public void shutdown() {
+            this.shutdown = true;
+        }
+
+        @Override
+        public void run() {
+            while (!shutdown) {
+                counter = (++counter % noImageImages.length);
+                image = noImageImages[counter];
+                repaint();
+
+                try { Thread.sleep(animationTime); } catch (InterruptedException e) {}
+            }
+        }
+
+    }
+            
+    public InfoPanel(String text, String[] noImageImageFileNames, int fps, int imageWidth, int imageHeight) {
+        this.text = text;
+        this.imageWidth = imageWidth;
+        this.imageHeight = imageHeight;
+        if (noImageImageFileNames == null || noImageImageFileNames.length == 0) {
+            this.noImageImages = null;
+        } else {
+            this.noImageImages = new BufferedImage[noImageImageFileNames.length];
+            for (int i = 0; i < noImageImageFileNames.length; ++i) {
+                this.noImageImages[i] = loadImage(noImageImageFileNames[i]);
+            }
+        }
+        this.animationTime = (fps == 0 ? 0 : 1000/fps);
+        this.setImage(null);
+    }
+
+    protected static BufferedImage loadImage(String fileName) {
+        BufferedImage image = null;
+        try {
+            InputStream in =
+                    FaceInfoPanel.class.getClassLoader().getResourceAsStream(fileName);
+            if (in != null) {
+                image = ImageIO.read(in);
+                in.close();
+            }
+        } catch (IOException ex) {
+            ex.printStackTrace();
+
+        }
+
+        return image;
+    }
+
+    @Override
+    public void paint(Graphics g) {
+        Graphics2D g2d = (Graphics2D) g;
+
+        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                    RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+
+        g2d.setBackground(new Color(0, 0, 0));
+        g2d.clearRect(0, 0, this.getWidth(), this.getHeight());
+
+        g2d.setColor(new Color(39, 53, 66));
+        g2d.fillRoundRect(2, 2, this.getWidth()-4, this.getHeight()-4, 10, 10);
+
+        g2d.setColor(new Color(118, 149, 174));
+        g2d.drawString(text, 10, 20);
+
+        g2d.setColor(new Color(81, 111, 137));
+        g2d.drawRect(this.getWidth()-11-imageWidth, 9, imageWidth+1, imageHeight+1);
+
+        if (image != null) {
+            g2d.drawImage(image,
+                    this.getWidth() - 10 - imageWidth, 10,
+                    imageWidth, imageHeight, null);
+        }
+
+        g2d.setStroke(new BasicStroke(2.0f));
+        g2d.setColor(new Color(81, 111, 137));
+        g2d.drawRoundRect(2, 2, this.getWidth()-4, this.getHeight()-4, 10, 10);
+    }
+
+    protected synchronized void setImage(BufferedImage image) {
+        if (image == null) {
+            if (this.noImageImages != null && this.noImageImages.length > 0) {
+                image =  this.noImageImages[0];
+                if (this.animationTime > 0) {
+                    if (this.animationThread == null)
+                        this.animationThread = new AnimationThread();
+                }
+            }
+        } else {
+            if (this.animationThread != null) {
+                this.animationThread.shutdown();
+                this.animationThread = null;
+            }
+        }
+        this.image = image;
+        this.repaint();
+    }
+
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/IntegralImageData.java b/Robust/src/Benchmarks/SSJava/EyeTracking/IntegralImageData.java
new file mode 100644 (file)
index 0000000..f6aad02
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+/**
+ * No description given.
+ * 
+ * @author Florian Frankenberger
+ */
+public class IntegralImageData {
+
+    private long[][] integral;
+    private Dimension dimension;
+
+    public IntegralImageData(BufferedImage bufferedImage) {
+        this.integral = new long[bufferedImage.getWidth()][bufferedImage.getHeight()];
+        this.dimension =  new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight());
+
+        int[] pixelBuffer = new int[bufferedImage.getWidth()*bufferedImage.getHeight()];
+        PixelGrabber pg = new PixelGrabber(
+                bufferedImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), pixelBuffer, 0, bufferedImage.getWidth());
+
+        try {
+            pg.grabPixels();
+        } catch (InterruptedException ie) {}
+
+        long[][] s = new long[bufferedImage.getWidth()][bufferedImage.getHeight()];
+        for (int y = 0; y < bufferedImage.getHeight(); ++y) {
+            for (int x = 0; x < bufferedImage.getWidth(); ++x) {
+                s[x][y] = (y-1 < 0 ? 0 : s[x][y-1]) + (pixelBuffer[y*bufferedImage.getWidth() + x] & 0xff);
+                this.integral[x][y] = (x-1 < 0 ? 0 : this.integral[x-1][y]) + s[x][y];
+            }
+        }
+        
+    }
+
+    public long getIntegralAt(int x, int y) {
+        return this.integral[x][y];
+    }
+
+    public Dimension getDimension() {
+        return this.dimension;
+    }
+
+    public int getWidth() {
+        return this.dimension.width;
+    }
+
+    public int getHeight() {
+        return this.dimension.height;
+    }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/JMFCaptureDevice.java b/Robust/src/Benchmarks/SSJava/EyeTracking/JMFCaptureDevice.java
new file mode 100644 (file)
index 0000000..5199a85
--- /dev/null
@@ -0,0 +1,213 @@
+/*\r
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)\r
+ * \r
+ * This file is part of LEA.\r
+ * \r
+ * LEA is free software: you can redistribute it and/or modify it under the\r
+ * terms of the GNU Lesser General Public License as published by the Free\r
+ * Software Foundation, either version 3 of the License, or (at your option) any\r
+ * later version.\r
+ * \r
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more\r
+ * details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+\r
+\r
+import java.awt.Dimension;\r
+import java.awt.image.BufferedImage;\r
+import java.io.IOException;\r
+import java.util.Vector;\r
+\r
+import javax.media.Buffer;\r
+import javax.media.CannotRealizeException;\r
+import javax.media.CaptureDeviceInfo;\r
+import javax.media.CaptureDeviceManager;\r
+import javax.media.Format;\r
+import javax.media.Manager;\r
+import javax.media.MediaLocator;\r
+import javax.media.NoDataSourceException;\r
+import javax.media.NoPlayerException;\r
+import javax.media.Player;\r
+import javax.media.control.FormatControl;\r
+import javax.media.control.FrameGrabbingControl;\r
+import javax.media.format.RGBFormat;\r
+import javax.media.format.VideoFormat;\r
+import javax.media.format.YUVFormat;\r
+import javax.media.protocol.CaptureDevice;\r
+import javax.media.protocol.DataSource;\r
+import javax.media.util.BufferToImage;\r
+\r
+import de.darkblue.lea.ifaces.ICaptureDevice;\r
+\r
+/**\r
+ * This class is a proxy to the <code>Java Media Framework</code>. You can use\r
+ * this class to make use of a <code>JMF</code> compatible webcam or\r
+ * other image source.\r
+ * <p>\r
+ * To receive a list of all available image sources just call the static\r
+ * method <code>getImageSources</code>.\r
+ * \r
+ * @author Florian Frankenberger\r
+ */\r
+public class JMFCaptureDevice implements ICaptureDevice {\r
+\r
+    private Player player;\r
+    private FrameGrabbingControl fgc;\r
+       \r
+    /**\r
+     * Initializes the <code>JMF</code> with the first available (<code>YUV</code> compatible) image source. The image\r
+     * source is then tested if it matches certain criteria - if not an <code>IllegalStateException</code>\r
+     * is thrown.\r
+     * <p>\r
+     * Criteria are:\r
+     * <li>provides <code>YUV</code> or <code>RGB</code> images\r
+     * <li>can provide images with <code>640x480</code> pixels\r
+     * \r
+     * @throws NoDataSourceException\r
+     * @throws NoPlayerException\r
+     * @throws CannotRealizeException\r
+     * @throws IOException\r
+     * @throws IllegalStateException if the data source does not match the criteria\r
+     */\r
+       public JMFCaptureDevice() throws NoDataSourceException, NoPlayerException, CannotRealizeException, IOException {\r
+               CaptureDeviceInfo imageSource = null;\r
+               \r
+        // get all image sources on the system that can supply us with at least YUV-images\r
+        CaptureDeviceInfo[] devices = getImageSourcesAvailable();\r
+\r
+        if (devices.length == 0) {\r
+            throw new IllegalStateException("No Webcams found on this system.");\r
+        }\r
+\r
+        // we use the first best (most of the time this is the webcam the user wants)\r
+        imageSource = devices[0];\r
+        \r
+               initImageSource(imageSource);\r
+       }\r
+       \r
+       /**\r
+        * Initializes the <code>JMF</code> with the given image source. An <code>IllegalStateException</code> is thrown\r
+        * if the image source does not the following criteria:\r
+     * <p>\r
+     * Criteria are:\r
+     * <li>provides <code>YUV</code> or <code>RGB</code> images\r
+     * <li>can provide images with <code>640x480</code> pixels\r
+        *\r
+        * @param imageSource the image source to use\r
+        * @throws NoDataSourceException\r
+        * @throws NoPlayerException\r
+        * @throws CannotRealizeException\r
+        * @throws IOException\r
+     * @throws IllegalStateException if the data source does not match the criteria\r
+        */\r
+       public JMFCaptureDevice(CaptureDeviceInfo imageSource) throws NoDataSourceException, NoPlayerException, CannotRealizeException, IOException {\r
+               initImageSource(imageSource);\r
+       }\r
+       \r
+    private void initImageSource(CaptureDeviceInfo imageSource) throws NoDataSourceException, IOException, NoPlayerException, CannotRealizeException {\r
+        if (imageSource == null) throw new IllegalStateException("Image source cannot be null");\r
+\r
+        // search the right format\r
+        VideoFormat matchingFormat = null;\r
+        VideoFormat alternateMatchingFormat = null;\r
+        for (Format format: imageSource.getFormats()) {\r
+            if (format instanceof VideoFormat) {\r
+                VideoFormat videoFormat = (VideoFormat) format;\r
+\r
+                if (videoFormat instanceof RGBFormat) {\r
+                    RGBFormat rgbFormat = (RGBFormat)videoFormat;\r
+                    Dimension size = rgbFormat.getSize();\r
+\r
+                    if (size.width == 640 && size.height == 480 &&\r
+                            rgbFormat.getBitsPerPixel() == 24) {\r
+                        matchingFormat = videoFormat;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                if (videoFormat instanceof YUVFormat) {\r
+                    YUVFormat rgbFormat = (YUVFormat)videoFormat;\r
+                    Dimension size = rgbFormat.getSize();\r
+\r
+                    if (size.width == 640 && size.height == 480) {\r
+                        alternateMatchingFormat = videoFormat;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        if (matchingFormat == null && alternateMatchingFormat != null)\r
+            matchingFormat = alternateMatchingFormat;\r
+\r
+        if (matchingFormat == null) {\r
+            throw new IllegalStateException ("Your image source does not support the 640x480 RGB/YUV format. This testenvironment relies on the fact, that your cam provides this resolution in this colorspace.");\r
+        }\r
+\r
+        MediaLocator mediaLocator = imageSource.getLocator();\r
+\r
+        DataSource dataSource = Manager.createDataSource(mediaLocator);\r
+        for (FormatControl formatControl: ((CaptureDevice) dataSource).getFormatControls()) {\r
+            if (formatControl == null) continue;\r
+            formatControl.setFormat(matchingFormat);\r
+        }\r
+\r
+        player = Manager.createRealizedPlayer(dataSource);\r
+\r
+        player.setRate(15);\r
+        player.start();\r
+\r
+        fgc = (FrameGrabbingControl) player.getControl("javax.media.control.FrameGrabbingControl");\r
+    }  \r
+    \r
+    /**\r
+     * Returns a vector of all image sources available on this system\r
+     * @return a vector of image sources\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+       public static CaptureDeviceInfo[] getImageSourcesAvailable() {\r
+        // get all image sources on the system that can supply us with at least YUV-images\r
+        Vector<CaptureDeviceInfo> devices = CaptureDeviceManager.getDeviceList(new VideoFormat(VideoFormat.YUV));\r
+        return devices.toArray(new CaptureDeviceInfo[0]);\r
+    }\r
+\r
+\r
+       /* (non-Javadoc)\r
+        * @see de.darkblue.lea.ICaptureDevice#getFrameRate()\r
+        */\r
+       @Override\r
+       public int getFrameRate() {\r
+               return 15;\r
+       }\r
+    \r
+       /* (non-Javadoc)\r
+        * @see de.darkblue.lea.ICaptureDevice#getImage()\r
+        */\r
+       @Override\r
+       public BufferedImage getImage() {\r
+        Buffer buffer = fgc.grabFrame();\r
+        \r
+        // Convert it to an image\r
+        BufferToImage btoi = new BufferToImage((VideoFormat)buffer.getFormat());\r
+        return (BufferedImage)btoi.createImage(buffer);\r
+    }\r
+\r
+       /* (non-Javadoc)\r
+        * @see de.darkblue.lea.ICaptureDevice#close()\r
+        */\r
+       @Override\r
+       public void close() {\r
+        if (player != null) {\r
+            player.close();\r
+            player.deallocate();\r
+        }              \r
+       }\r
+\r
+\r
+       \r
+       \r
+}\r
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/LEA.java b/Robust/src/Benchmarks/SSJava/EyeTracking/LEA.java
new file mode 100644 (file)
index 0000000..c51fd07
--- /dev/null
@@ -0,0 +1,176 @@
+import Benchmarks.oooJava.barneshut.FileInputStream;
+
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * This is the main class of LEA.
+ * <p>
+ * It uses a face detection algorithm to find an a face within the provided
+ * image(s). Then it searches for the eye in a region where it most likely
+ * located and traces its position relative to the face and to the last known
+ * position. The movements are estimated by comparing more than one movement. If
+ * a movement is distinctly pointing to a direction it is recognized and all
+ * listeners get notified.
+ * <p>
+ * The notification is designed as observer pattern. You simply call
+ * <code>addEyeMovementListener(IEyeMovementListener)</code> to add an
+ * implementation of <code>IEyeMovementListener</code> to LEA. When a face is
+ * recognized/lost or whenever an eye movement is detected LEA will call the
+ * appropriate methods of the listener
+ * <p>
+ * LEA also needs an image source implementing the <code>ICaptureDevice</code>.
+ * One image source proxy to the <code>Java Media Framework</code> is included (
+ * <code>JMFCaptureDevice</code>).
+ * <p>
+ * Example (for using LEA with <code>Java Media Framework</code>):
+ * <p>
+ * <code>
+ * LEA lea = new LEA(new JMFCaptureDevice(), true);
+ * </code>
+ * <p>
+ * This will start LEA with the first available JMF datasource with an extra
+ * status window showing if face/eye has been detected successfully. Please note
+ * that face detection needs about 2 seconds to find a face. After detection the
+ * following face detection is much faster.
+ * 
+ * @author Florian Frankenberger
+ */
+public class LEA {
+
+  private boolean showStatusWindow;
+
+  private boolean shutdown = false;
+
+  // private LEAImplementation implementation = new LEAImplementation();
+
+  // private ImageProcessor imageProcessor;
+  //
+  // private class ImageProcessor extends TimedThread {
+  //
+  // private FaceAndEyePosition lastPositions = new FaceAndEyePosition(null,
+  // null);
+  // private DeviationScanner deviationScanner = new DeviationScanner();
+  // private int counter = 0;
+  //
+  // private int fps;
+  //
+  // public ImageProcessor(int fps) {
+  // super(fps);
+  // this.fps = fps;
+  // }
+  //
+  // @Override
+  // public void doRun() {
+  //
+  // BufferedImage image = captureDevice.getImage();
+  // if (image == null)
+  // return;
+  //
+  // try {
+  // FaceAndEyePosition positions = implementation.getEyePosition(image);
+  //
+  // if (((lastPositions.getFacePosition() == null &&
+  // positions.getFacePosition() != null) || (lastPositions
+  // .getFacePosition() != null && positions.getFacePosition() == null)) ||
+  // counter++ > fps) {
+  //
+  // if ((lastPositions.getFacePosition() == null && positions.getFacePosition()
+  // != null)
+  // || (lastPositions.getFacePosition() != null && positions.getFacePosition()
+  // == null)) {
+  // if (positions.getFacePosition() != null) {
+  // notifyEyeMovementListenerFaceDetected();
+  // } else {
+  // notifyEyeMovementListenerFaceLost();
+  // }
+  // }
+  // counter = 0;
+  // if (statusWindow != null)
+  // statusWindow.getFaceInfoPanel().setFace(image,
+  // positions.getFacePosition());
+  // }
+  //
+  // if (positions.getEyePosition() != null) {
+  // if (statusWindow != null) {
+  // statusWindow.getEyeInfoPanel().setEyePosition(image,
+  // positions.getFacePosition(),
+  // positions.getEyePosition());
+  // }
+  // deviationScanner.addEyePosition(positions.getEyePosition());
+  // Deviation deviation =
+  // deviationScanner.scanForDeviation(positions.getFacePosition());//
+  // positions.getEyePosition().getDeviation(lastPositions.getEyePosition());
+  //
+  // if (deviation != Deviation.NONE) {
+  // notifyEyeMovementListenerEyeMoved(deviation);
+  // }
+  //
+  // } else {
+  // if (statusWindow != null)
+  // statusWindow.getEyeInfoPanel().setDeviation(null);
+  // }
+  //
+  // lastPositions = positions;
+  // } catch (Exception e) {
+  // e.printStackTrace();
+  // try {
+  // close();
+  // } catch (Exception e2) {
+  // }
+  // }
+  // }
+  //
+  // public synchronized void clearDeviationScanner() {
+  // this.deviationScanner.clear();
+  // }
+  //
+  // }
+
+  public LEA() {
+    // this.imageProcessor = new
+    // ImageProcessor(this.captureDevice.getFrameRate());
+    // this.imageProcessor.start();
+    LEAImplementation impl = new LEAImplementation();
+    System.out.println("Done.");
+  }
+
+  /**
+   * Clears the internal movement buffer. If you just capture some of the eye
+   * movements you should call this every time you start recording the
+   * movements. Otherwise you may get notified for movements that took place
+   * BEFORE you started recording.
+   */
+  public void clear() {
+    // this.imageProcessor.clearDeviationScanner();
+  }
+
+  /**
+   * To test LEA with the first capture device from the
+   * <code>Java Media Framework</code> just start from here.
+   * 
+   * @param args
+   * @throws Exception
+   */
+  public static void main(String[] args) throws Exception {
+    LEA lea = new LEA();
+
+  }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/LEAImplementation.java b/Robust/src/Benchmarks/SSJava/EyeTracking/LEAImplementation.java
new file mode 100644 (file)
index 0000000..39d1647
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * No description given.
+ * 
+ * @author Florian Frankenberger
+ */
+public class LEAImplementation {
+
+  // private ClassifierTree classifierTree = null;
+
+  // private Rectangle2D lastRectangle;
+
+  public LEAImplementation() {
+    this.loadFaceData();
+  }
+
+  // public FaceAndEyePosition getEyePosition(BufferedImage image) {
+  // if (image == null)
+  // return null;
+  //
+  // Rectangle2D faceRect = this.classifierTree.locateFaceRadial(image,
+  // lastRectangle);
+  // EyePosition eyePosition = null;
+  // if (faceRect != null) {
+  //
+  // lastRectangle = faceRect;
+  // Point point = readEyes(image, faceRect);
+  // if (point != null) {
+  // eyePosition = new EyePosition(point, faceRect);
+  // }
+  // }
+  //
+  // return new FaceAndEyePosition(faceRect, eyePosition);
+  // }
+
+  public boolean needsCalibration() {
+    return false;
+  }
+
+  /**
+   * This method loads the faceData from a file called facedata.dat which should
+   * be within the jar-file
+   */
+  private void loadFaceData() {
+
+    FileInputStream inputFile = new FileInputStream("facedata.dat");
+
+    int numClassifier = Integer.parseInt(inputFile.readLine());
+    System.out.println("numClassifier=" + numClassifier);
+    for (int c = 0; c < numClassifier; c++) {
+
+      int numArea = Integer.parseInt(inputFile.readLine());
+      Classifier classifier = new Classifier(numArea);
+      // parsing areas
+      for (int idx = 0; idx < numArea; idx++) {
+        // 54,54,91,62,296.0
+        Point fromPoint = new Point();
+        Point toPoint = new Point();
+        fromPoint.x  = Integer.parseInt(inputFile.readLine());
+        fromPoint.y = Integer.parseInt(inputFile.readLine());
+        toPoint.x = Integer.parseInt(inputFile.readLine());
+        toPoint.y = Integer.parseInt(inputFile.readLine());
+        float size = Float.parseFloat(inputFile.readLine());
+        ScanArea area = new ScanArea(fromPoint, toPoint, size);
+        classifier.setScanArea(idx, area);
+      }
+
+      // parsing possibilities face yes
+      float array[] = new float[numArea];
+      for (int idx = 0; idx < numArea; idx++) {
+        array[idx] = Float.parseFloat(inputFile.readLine());
+      }
+      classifier.setPossibilitiesFaceYes(array);
+
+      // parsing possibilities face no
+      for (int idx = 0; idx < numArea; idx++) {
+        array[idx] = Float.parseFloat(inputFile.readLine());
+      }
+      classifier.setPossibilitiesFaceNo(array);
+      classifier.setPossibilityFaceYes(Integer.parseInt(inputFile.readLine()));
+      classifier.setPossibilityFaceNo(Integer.parseInt(inputFile.readLine()));
+
+    }
+  }
+  // private Point readEyes(BufferedImage image, Rectangle2D rect) {
+  //
+  // // now we cluster the black image points and try to find the inner eye
+  // /*
+  // * BlackHoleDetector bhd = new BlackHoleDetector(image, rect);
+  // * bhd.detect(20);
+  // *
+  // * return bhd.getPosition();
+  // */
+  //
+  // EyeDetector ed = new EyeDetector(image, rect);
+  // return ed.detectEye();
+  // }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/LEAStatusWindow.java b/Robust/src/Benchmarks/SSJava/EyeTracking/LEAStatusWindow.java
new file mode 100644 (file)
index 0000000..105dc67
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ *
+ * @author Florian
+ */
+class LEAStatusWindow extends javax.swing.JFrame {
+
+       private static final long serialVersionUID = 6565861506173488477L;
+       
+       /** Creates new form LEAStatusWindow */
+    public LEAStatusWindow() {
+        initComponents();
+        this.setLocationRelativeTo(null);
+    }
+
+    public FaceInfoPanel getFaceInfoPanel() {
+        return (FaceInfoPanel)this.faceInfoPanel;
+    }
+
+    public EyeInfoPanel getEyeInfoPanel() {
+        return (EyeInfoPanel)this.eyeInfoPanel;
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jPanel1 = new javax.swing.JPanel();
+        faceInfoPanel = new FaceInfoPanel();
+        eyeInfoPanel = new EyeInfoPanel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+        setTitle("LEA Status Window");
+        setBackground(new java.awt.Color(0, 0, 0));
+        setResizable(false);
+
+        jPanel1.setBackground(new java.awt.Color(0, 0, 0));
+
+        javax.swing.GroupLayout faceInfoPanelLayout = new javax.swing.GroupLayout(faceInfoPanel);
+        faceInfoPanel.setLayout(faceInfoPanelLayout);
+        faceInfoPanelLayout.setHorizontalGroup(
+            faceInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 468, Short.MAX_VALUE)
+        );
+        faceInfoPanelLayout.setVerticalGroup(
+            faceInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 119, Short.MAX_VALUE)
+        );
+
+        javax.swing.GroupLayout eyeInfoPanelLayout = new javax.swing.GroupLayout(eyeInfoPanel);
+        eyeInfoPanel.setLayout(eyeInfoPanelLayout);
+        eyeInfoPanelLayout.setHorizontalGroup(
+            eyeInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 468, Short.MAX_VALUE)
+        );
+        eyeInfoPanelLayout.setVerticalGroup(
+            eyeInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 60, Short.MAX_VALUE)
+        );
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(eyeInfoPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(faceInfoPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(faceInfoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(eyeInfoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JPanel eyeInfoPanel;
+    private javax.swing.JPanel faceInfoPanel;
+    private javax.swing.JPanel jPanel1;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/Point.java b/Robust/src/Benchmarks/SSJava/EyeTracking/Point.java
new file mode 100644 (file)
index 0000000..cfc3eaf
--- /dev/null
@@ -0,0 +1,14 @@
+public class Point {
+
+  public int x;
+  public int y;
+
+  public Point(int x, int y) {
+    this.x = x;
+    this.y = y;
+  }
+
+  public Point() {
+  }
+
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/ScanArea.java b/Robust/src/Benchmarks/SSJava/EyeTracking/ScanArea.java
new file mode 100644 (file)
index 0000000..df3c842
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)
+ * 
+ * This file is part of LEA.
+ * 
+ * LEA is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * 
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * 
+ * @author Florian
+ */
+public class ScanArea {
+
+  private Point fromPoint;
+  private Point toPoint;
+  private float size;
+
+  /**
+   * Imagine you want to classify an image with 100px x 100px what would be the
+   * scanarea in this kind of image. That size gets automatically scalled to fit
+   * bigger images
+   * 
+   * @param fromPoint
+   * @param toPoint
+   */
+  public ScanArea(Point fromPoint, Point toPoint) {
+    this.fromPoint = fromPoint;
+    this.toPoint = toPoint;
+
+    this.size = (this.toPoint.x - this.fromPoint.x) * (this.toPoint.y - this.fromPoint.y);
+  }
+
+  public ScanArea(Point fromPoint, Point toPoint, float size) {
+    this.fromPoint = fromPoint;
+    this.toPoint = toPoint;
+    this.size = size;
+  }
+
+  public ScanArea(int fromX, int fromY, int width, int height) {
+    this(new Point(fromX, fromY), new Point(fromX + width, fromY + height));
+  }
+
+  public int getFromX(float scaleFactor) {
+    return (int) (this.fromPoint.x * scaleFactor);
+  }
+
+  public int getFromY(float scaleFactor) {
+    return (int) (this.fromPoint.y * scaleFactor);
+  }
+
+  public int getToX(float scaleFactor) {
+    return (int) (this.toPoint.x * scaleFactor);
+  }
+
+  public int getToY(float scaleFactor) {
+    return (int) (this.toPoint.y * scaleFactor);
+  }
+
+  public int getSize(float scaleFactor) {
+    return (int) (this.size * Math.pow(scaleFactor, 2));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    ScanArea other = (ScanArea) o;
+
+    return pointsWithin(other.fromPoint.x, other.toPoint.x, this.fromPoint.x, this.toPoint.x)
+        && pointsWithin(other.fromPoint.y, other.toPoint.y, this.fromPoint.y, this.toPoint.y);
+  }
+
+  private static boolean pointsWithin(int pointA1, int pointA2, int pointB1, int pointB2) {
+    boolean within = false;
+    within = within || (pointB1 >= pointA1 && pointB1 <= pointA2);
+    within = within || (pointB2 >= pointA1 && pointB2 <= pointA2);
+    within = within || (pointA1 >= pointB1 && pointA1 <= pointB2);
+    within = within || (pointA2 >= pointB1 && pointA2 <= pointB2);
+
+    return within;
+  }
+
+  // private boolean checkPoints(ScanArea a, ScanArea b) {
+  // Point[] pointsToCheck = new Point[] {
+  // a.fromPoint, a.toPoint,
+  // new Point (a.fromPoint.x, a.toPoint.y),
+  // new Point (a.toPoint.x, a.fromPoint.y)
+  // };
+  // for (Point point: pointsToCheck) {
+  // if (point.x >= b.fromPoint.x && point.x <= b.toPoint.x &&
+  // point.y >= b.fromPoint.y && point.y <= b.toPoint.y) return true;
+  // }
+  //
+  // return false;
+  // }
+
+  public String toString() {
+    String str = "";
+    str += "fromPoint=(" + fromPoint.x + "," + fromPoint.y + ")";
+    str += "\n";
+    str += "toPoint=(" + toPoint.x + "," + toPoint.y + ")";
+    str += "\n";
+    return str;
+  }
+}
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/StaticSizeArrayList.java b/Robust/src/Benchmarks/SSJava/EyeTracking/StaticSizeArrayList.java
new file mode 100644 (file)
index 0000000..168369c
--- /dev/null
@@ -0,0 +1,72 @@
+/*\r
+ * Copyright 2009 (c) Florian Frankenberger (darkblue.de)\r
+ * \r
+ * This file is part of LEA.\r
+ * \r
+ * LEA is free software: you can redistribute it and/or modify it under the\r
+ * terms of the GNU Lesser General Public License as published by the Free\r
+ * Software Foundation, either version 3 of the License, or (at your option) any\r
+ * later version.\r
+ * \r
+ * LEA is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more\r
+ * details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with LEA. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+\r
+\r
+/**\r
+ * An array with just a static size. If you add more than\r
+ * the capacity holds the oldest element gets removed.\r
+ * <p>\r
+ * This List is implemented as an ring buffer array.\r
+ * <p>\r
+ * TODO: implement the <code>List</code> interface\r
+ * \r
+ * @author Florian Frankenberger\r
+ */\r
+public class StaticSizeArrayList<T> {\r
+\r
+       private Object[] buffer;\r
+       private int startPos = 0;\r
+       private int pos = 0;\r
+       private int size = 0;\r
+       \r
+       public StaticSizeArrayList(int size) {\r
+               this.buffer = new Object[size];\r
+       }\r
+       \r
+       public synchronized void add(T item) {\r
+               this.buffer[pos] = item;\r
+               pos = ++pos % buffer.length;\r
+               if (size < buffer.length) {\r
+                       size++;\r
+               } else {\r
+                       this.startPos = ++this.startPos % this.buffer.length;\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       public synchronized T get(int i) {\r
+               if (i >= this.size)\r
+                       throw new ArrayIndexOutOfBoundsException("Size is "+this.size+" but tried to access item "+i);\r
+               \r
+               int acPos = (this.startPos + i) % this.buffer.length;\r
+               \r
+               return (T)this.buffer[acPos];\r
+       }\r
+       \r
+       public synchronized void clear() {\r
+               this.startPos = 0;\r
+               this.pos = 0;\r
+               this.size = 0;\r
+       }\r
+       \r
+       public synchronized int size() {\r
+               return this.size;\r
+       }\r
+       \r
+}\r
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/facedata.dat b/Robust/src/Benchmarks/SSJava/EyeTracking/facedata.dat
new file mode 100644 (file)
index 0000000..a38e0e8
--- /dev/null
@@ -0,0 +1,2090 @@
+8
+6
+54
+54
+91
+62
+296.0
+25
+47
+39
+66
+266.0
+12
+29
+45
+38
+297.0
+49
+65
+62
+86
+273.0
+58
+38
+90
+47
+288.0
+49
+5
+61
+28
+276.0
+0.78447694
+0.51399076
+0.019654196
+0.038308397
+0.7471684
+0.89640224
+0.43222174
+0.5485019
+0.56839997
+0.44714534
+0.44154882
+0.5034207
+107
+3210
+7
+43
+65
+57
+71
+84.0
+42
+55
+81
+58
+117.0
+76
+21
+79
+49
+84.0
+54
+27
+69
+33
+90.0
+43
+40
+58
+46
+90.0
+25
+73
+57
+76
+96.0
+36
+21
+60
+25
+96.0
+0.57928056
+0.9243835
+0.5139905
+0.29946703
+0.30879453
+0.17821494
+0.6632244
+0.4956475
+0.49564773
+0.4794796
+0.49347022
+0.5314026
+0.54974556
+0.561873
+107
+3210
+9
+35
+74
+54
+79
+95.0
+12
+61
+23
+70
+99.0
+60
+45
+69
+56
+99.0
+58
+26
+87
+30
+116.0
+27
+60
+49
+65
+110.0
+53
+45
+59
+61
+96.0
+44
+38
+70
+42
+104.0
+48
+18
+75
+22
+108.0
+29
+31
+62
+34
+99.0
+0.112925306
+0.5979346
+0.93371063
+0.07561684
+0.41139242
+0.45802805
+0.73784137
+0.4953364
+0.532645
+0.50652957
+0.5596948
+0.4552287
+0.46455583
+0.54508185
+0.45616162
+0.48165566
+0.4869416
+0.5376199
+107
+3210
+13
+32
+32
+60
+36
+112.0
+28
+18
+46
+24
+108.0
+36
+52
+71
+55
+105.0
+22
+45
+55
+48
+99.0
+59
+37
+92
+40
+99.0
+30
+60
+59
+64
+116.0
+73
+67
+92
+72
+95.0
+67
+11
+73
+27
+96.0
+55
+82
+75
+87
+100.0
+32
+37
+56
+41
+96.0
+6
+27
+14
+39
+96.0
+58
+44
+82
+48
+96.0
+41
+72
+45
+96
+96.0
+0.3927383
+0.17821503
+0.69120574
+0.6165889
+0.8590937
+0.28081292
+0.79380393
+0.08494394
+0.70985985
+0.37408417
+0.14090677
+0.93371063
+0.280813
+0.5202099
+0.5513008
+0.48352194
+0.5264276
+0.4269359
+0.51119345
+0.43066725
+0.45709372
+0.4431036
+0.51896566
+0.5761743
+0.43595245
+0.4853875
+107
+3210
+21
+70
+43
+89
+46
+57.0
+39
+37
+54
+40
+45.0
+33
+60
+53
+63
+60.0
+52
+67
+59
+74
+49.0
+51
+14
+55
+25
+44.0
+13
+73
+26
+77
+52.0
+71
+69
+84
+73
+52.0
+59
+35
+66
+42
+49.0
+13
+35
+17
+46
+44.0
+35
+23
+38
+38
+45.0
+47
+51
+63
+54
+48.0
+58
+56
+77
+59
+57.0
+33
+72
+40
+79
+49.0
+39
+41
+54
+44
+45.0
+8
+57
+14
+65
+48.0
+58
+10
+66
+16
+48.0
+43
+83
+62
+86
+57.0
+20
+25
+28
+31
+48.0
+35
+47
+50
+50
+45.0
+70
+47
+81
+51
+44.0
+10
+52
+24
+56
+56.0
+0.9243835
+0.17821491
+0.13157943
+0.5419719
+0.94303775
+0.16888793
+0.80313104
+0.6538973
+0.2528317
+0.2714859
+0.5979345
+0.9803462
+0.03830837
+0.1222525
+0.07561681
+0.9243835
+0.50466365
+0.001
+0.21552329
+0.9803462
+0.5233179
+0.41791958
+0.49968916
+0.50497437
+0.44185993
+0.48569784
+0.5497462
+0.42507058
+0.44652277
+0.5702664
+0.5276726
+0.45025402
+0.4306672
+0.500933
+0.49657974
+0.550678
+0.46766484
+0.4685978
+0.5634273
+0.5105703
+0.42569247
+0.5606273
+107
+3210
+37
+35
+20
+45
+24
+40.0
+28
+58
+44
+61
+48.0
+29
+43
+45
+46
+48.0
+50
+53
+53
+65
+36.0
+73
+64
+75
+82
+36.0
+22
+70
+37
+73
+45.0
+56
+51
+62
+57
+36.0
+19
+22
+23
+31
+36.0
+16
+63
+18
+81
+36.0
+79
+58
+81
+76
+36.0
+13
+52
+29
+55
+48.0
+46
+8
+61
+11
+45.0
+53
+38
+68
+41
+45.0
+84
+37
+86
+55
+36.0
+38
+25
+51
+28
+39.0
+69
+28
+70
+63
+35.0
+32
+62
+45
+65
+39.0
+64
+14
+80
+17
+48.0
+39
+70
+49
+74
+40.0
+15
+33
+19
+42
+36.0
+49
+46
+59
+50
+40.0
+41
+13
+51
+17
+40.0
+38
+86
+46
+91
+40.0
+79
+22
+82
+34
+36.0
+66
+88
+74
+93
+40.0
+54
+73
+56
+91
+36.0
+2
+47
+7
+54
+35.0
+57
+81
+65
+86
+40.0
+36
+29
+44
+34
+40.0
+3
+60
+15
+63
+36.0
+27
+35
+34
+40
+35.0
+57
+59
+59
+77
+36.0
+64
+64
+69
+71
+35.0
+26
+14
+28
+32
+36.0
+85
+58
+94
+62
+36.0
+51
+30
+57
+36
+36.0
+42
+80
+49
+85
+35.0
+0.24350454
+0.44870088
+0.36475706
+0.7285142
+0.9057293
+0.29946718
+0.32744858
+0.028981311
+0.3834112
+0.961692
+0.87774795
+0.9057293
+0.6445702
+0.88707507
+0.54197204
+0.99900043
+0.1315795
+0.45802796
+0.48600936
+0.16888788
+0.6725514
+0.93371063
+0.45802793
+0.18754214
+0.60726196
+0.4020654
+0.010327146
+0.52331775
+0.31812155
+0.07561681
+0.8590937
+0.3181214
+0.70053285
+0.001
+0.52331793
+0.5419721
+0.38341117
+0.5376197
+0.5286042
+0.52269644
+0.46206897
+0.4185414
+0.5307805
+0.44310337
+0.5584525
+0.53886336
+0.41698694
+0.546638
+0.5080832
+0.44963196
+0.42444828
+0.51274693
+0.42382675
+0.51492363
+0.45243058
+0.48103434
+0.5528546
+0.46984145
+0.5180326
+0.49067295
+0.44590148
+0.43968338
+0.44154894
+0.56404704
+0.44869992
+0.5335793
+0.5453939
+0.5528552
+0.42071792
+0.42942348
+0.5472579
+0.42413813
+0.47077382
+0.4866306
+107
+3210
+69
+29
+33
+31
+44
+22.0
+75
+35
+83
+38
+24.0
+33
+36
+34
+57
+21.0
+32
+71
+36
+77
+24.0
+70
+34
+74
+40
+24.0
+51
+84
+56
+89
+25.0
+35
+26
+39
+32
+24.0
+25
+60
+34
+63
+27.0
+41
+51
+46
+56
+25.0
+49
+23
+55
+27
+24.0
+43
+23
+44
+44
+21.0
+72
+57
+75
+64
+21.0
+26
+50
+32
+54
+24.0
+17
+55
+24
+58
+21.0
+5
+42
+11
+46
+24.0
+64
+19
+70
+23
+24.0
+51
+47
+57
+51
+24.0
+20
+86
+28
+89
+24.0
+30
+10
+33
+17
+21.0
+71
+25
+78
+28
+21.0
+42
+10
+49
+13
+21.0
+64
+58
+68
+64
+24.0
+24
+71
+29
+76
+25.0
+16
+34
+21
+39
+25.0
+35
+51
+39
+57
+24.0
+57
+67
+58
+88
+21.0
+75
+18
+83
+21
+24.0
+64
+6
+67
+13
+21.0
+71
+81
+74
+88
+21.0
+37
+4
+40
+11
+21.0
+90
+51
+98
+54
+24.0
+35
+58
+42
+61
+21.0
+80
+53
+85
+58
+25.0
+25
+14
+29
+20
+24.0
+43
+80
+51
+83
+24.0
+36
+86
+42
+90
+24.0
+7
+60
+16
+63
+27.0
+21
+27
+30
+30
+27.0
+53
+31
+56
+38
+21.0
+49
+66
+54
+71
+25.0
+52
+4
+61
+7
+27.0
+58
+22
+62
+28
+24.0
+39
+73
+44
+78
+25.0
+27
+64
+32
+69
+25.0
+76
+68
+78
+79
+22.0
+54
+61
+62
+64
+24.0
+54
+53
+59
+58
+25.0
+61
+70
+64
+77
+21.0
+43
+45
+48
+50
+25.0
+62
+83
+70
+86
+24.0
+16
+74
+18
+85
+22.0
+22
+42
+24
+53
+22.0
+15
+18
+21
+22
+24.0
+6
+51
+14
+54
+24.0
+81
+61
+82
+82
+21.0
+41
+92
+50
+95
+27.0
+75
+41
+81
+45
+24.0
+58
+46
+67
+49
+27.0
+52
+13
+59
+16
+21.0
+87
+42
+89
+53
+22.0
+27
+78
+35
+81
+24.0
+46
+61
+52
+65
+24.0
+56
+42
+64
+45
+24.0
+35
+42
+42
+45
+21.0
+61
+33
+66
+38
+25.0
+69
+49
+76
+52
+21.0
+56
+94
+61
+99
+25.0
+30
+86
+34
+92
+24.0
+84
+32
+92
+35
+24.0
+0.89640224
+0.44870088
+0.803131
+0.178215
+0.72851413
+0.5606263
+0.25283164
+0.8964022
+0.20619617
+0.95236486
+0.094271086
+0.99900043
+0.9803462
+0.83111244
+0.1595608
+0.13157965
+0.58860755
+0.1968692
+0.4673551
+0.11292524
+0.9243835
+0.8124582
+0.28081292
+0.13157965
+0.1968692
+0.29014012
+0.1409067
+0.89640224
+0.7005328
+0.87774795
+0.29014015
+0.12225243
+0.9150564
+0.001
+0.280813
+0.3367756
+0.1409067
+0.001
+0.4487009
+0.7378413
+0.89640224
+0.37408397
+0.09427106
+0.5419721
+0.7844768
+0.31812128
+0.3274484
+0.3367757
+0.4020654
+0.5886074
+0.16888782
+0.94303775
+0.08494392
+0.18754199
+0.81245816
+0.7844769
+0.95236486
+0.66322434
+0.9243835
+0.7844769
+0.09427106
+0.5233177
+0.4673551
+0.19686913
+0.6165888
+0.9896733
+0.75649554
+0.26215878
+0.280813
+0.54601437
+0.42662486
+0.5239404
+0.51741076
+0.44030485
+0.46548912
+0.53233284
+0.53264564
+0.5055968
+0.49471414
+0.50404143
+0.42320526
+0.5413512
+0.5450827
+0.55627555
+0.44776708
+0.46393427
+0.54010737
+0.56498075
+0.4434139
+0.5242502
+0.43066725
+0.5410397
+0.54912555
+0.52922535
+0.4328436
+0.44869947
+0.47139576
+0.42475927
+0.54850155
+0.42040655
+0.5174102
+0.42507055
+0.5609385
+0.48880714
+0.497513
+0.5450818
+0.5584515
+0.46144667
+0.4505651
+0.4962689
+0.45087564
+0.49782407
+0.5220751
+0.42724708
+0.4353308
+0.4555398
+0.43657473
+0.5043537
+0.43875065
+0.53824323
+0.530781
+0.56187207
+0.5584515
+0.41667587
+0.48663133
+0.43035597
+0.44403616
+0.4869417
+0.42040643
+0.52922606
+0.47605973
+0.45585036
+0.52735937
+0.44683382
+0.43284342
+0.45989278
+0.5198991
+0.4384393
+107
+3210
+133
+29
+21
+30
+41
+20.0
+24
+73
+26
+83
+20.0
+25
+20
+27
+30
+20.0
+15
+50
+20
+54
+20.0
+86
+28
+89
+35
+21.0
+37
+37
+43
+41
+24.0
+49
+54
+53
+59
+20.0
+33
+56
+39
+60
+24.0
+83
+28
+84
+48
+20.0
+58
+44
+65
+47
+21.0
+77
+73
+85
+76
+24.0
+49
+18
+58
+21
+27.0
+51
+92
+56
+96
+20.0
+41
+45
+49
+48
+24.0
+12
+63
+20
+66
+24.0
+67
+9
+76
+12
+27.0
+69
+26
+76
+29
+21.0
+29
+62
+36
+65
+21.0
+41
+9
+50
+12
+27.0
+67
+46
+69
+56
+20.0
+53
+48
+57
+53
+20.0
+29
+74
+38
+77
+27.0
+53
+71
+56
+78
+21.0
+10
+46
+18
+49
+24.0
+42
+63
+44
+73
+20.0
+39
+20
+48
+23
+27.0
+24
+42
+31
+45
+21.0
+63
+6
+64
+26
+20.0
+24
+46
+26
+56
+20.0
+50
+43
+55
+47
+20.0
+25
+10
+31
+14
+24.0
+64
+86
+70
+90
+24.0
+75
+39
+78
+46
+21.0
+65
+73
+72
+76
+21.0
+26
+68
+35
+71
+27.0
+44
+36
+48
+41
+20.0
+68
+61
+76
+64
+24.0
+21
+57
+25
+62
+20.0
+56
+54
+63
+57
+21.0
+47
+74
+50
+81
+21.0
+37
+28
+43
+32
+24.0
+81
+50
+82
+70
+20.0
+54
+29
+63
+32
+27.0
+70
+79
+75
+83
+20.0
+55
+12
+61
+16
+24.0
+46
+87
+54
+90
+24.0
+33
+29
+35
+39
+20.0
+31
+46
+40
+49
+27.0
+20
+77
+23
+84
+21.0
+93
+37
+97
+42
+20.0
+83
+61
+91
+64
+24.0
+53
+3
+60
+6
+21.0
+65
+37
+72
+40
+21.0
+54
+38
+60
+42
+24.0
+14
+73
+17
+80
+21.0
+7
+55
+12
+59
+20.0
+46
+25
+48
+35
+20.0
+35
+3
+37
+13
+20.0
+19
+32
+26
+35
+21.0
+80
+22
+84
+27
+20.0
+80
+78
+86
+82
+24.0
+64
+27
+68
+32
+20.0
+74
+55
+80
+59
+24.0
+57
+63
+59
+73
+20.0
+89
+53
+96
+56
+21.0
+80
+37
+82
+47
+20.0
+45
+65
+49
+70
+20.0
+45
+91
+49
+96
+20.0
+22
+86
+31
+89
+27.0
+57
+74
+60
+81
+21.0
+66
+19
+73
+22
+21.0
+37
+83
+42
+87
+20.0
+29
+50
+33
+55
+20.0
+10
+31
+13
+38
+21.0
+13
+57
+18
+61
+20.0
+86
+46
+91
+50
+20.0
+40
+74
+45
+78
+20.0
+86
+70
+90
+75
+20.0
+12
+26
+19
+29
+21.0
+28
+17
+35
+20
+21.0
+39
+50
+45
+54
+24.0
+2
+48
+8
+52
+24.0
+14
+39
+20
+43
+24.0
+39
+13
+46
+16
+21.0
+73
+49
+77
+54
+20.0
+30
+91
+39
+94
+27.0
+69
+31
+73
+36
+20.0
+66
+77
+69
+84
+21.0
+64
+53
+66
+63
+20.0
+18
+21
+24
+25
+24.0
+29
+78
+34
+82
+20.0
+76
+77
+79
+84
+21.0
+1
+40
+9
+43
+24.0
+51
+79
+56
+83
+20.0
+59
+33
+66
+36
+21.0
+50
+24
+56
+28
+24.0
+46
+60
+51
+64
+20.0
+38
+63
+41
+70
+21.0
+66
+41
+74
+44
+24.0
+62
+92
+66
+97
+20.0
+4
+67
+12
+70
+24.0
+81
+14
+86
+18
+20.0
+75
+85
+82
+88
+21.0
+8
+74
+13
+78
+20.0
+31
+21
+36
+25
+20.0
+14
+16
+19
+20
+20.0
+92
+60
+96
+65
+20.0
+53
+63
+56
+70
+21.0
+13
+68
+20
+71
+21.0
+9
+21
+15
+25
+24.0
+50
+33
+53
+40
+21.0
+43
+55
+48
+59
+20.0
+71
+84
+74
+91
+21.0
+62
+66
+68
+70
+24.0
+70
+67
+74
+72
+20.0
+78
+28
+82
+33
+20.0
+54
+59
+62
+62
+24.0
+21
+64
+23
+74
+20.0
+5
+60
+11
+64
+24.0
+86
+36
+89
+43
+21.0
+91
+28
+94
+35
+21.0
+75
+15
+79
+20
+20.0
+59
+48
+65
+52
+24.0
+3
+33
+8
+37
+20.0
+27
+56
+31
+61
+20.0
+86
+66
+94
+69
+24.0
+57
+86
+62
+90
+20.0
+45
+4
+50
+8
+20.0
+52
+7
+61
+10
+27.0
+70
+47
+72
+57
+20.0
+92
+44
+98
+48
+24.0
+61
+73
+63
+83
+20.0
+21
+36
+26
+40
+20.0
+0.12225246
+0.37408406
+0.06628969
+0.64457035
+0.23417756
+0.26215884
+0.7658226
+0.374084
+0.47668225
+0.5792806
+0.76582265
+0.961692
+0.8124583
+0.2994673
+0.47668222
+0.8870751
+0.084943935
+0.53264505
+0.93371063
+0.99900043
+0.47668222
+0.22485054
+0.3087944
+0.5606262
+0.24350454
+0.5979348
+0.93371063
+0.8031311
+0.99900043
+0.6165891
+0.6259161
+0.70986
+0.961692
+0.6259158
+0.29946718
+0.23417749
+0.99900043
+0.9803462
+0.374084
+0.08494389
+0.29946724
+0.95236486
+0.48600927
+0.7098599
+0.9150564
+0.47668222
+0.5886074
+0.42071956
+0.38341117
+0.34610268
+0.65389746
+0.89640224
+0.877748
+0.34610277
+0.15956078
+0.14090666
+0.54197186
+0.87774795
+0.12225238
+0.1968692
+0.5606262
+0.3367757
+0.99900043
+0.4113925
+0.40206534
+0.9243835
+0.7005328
+0.8217853
+0.2528317
+0.09427108
+0.15956095
+0.29946703
+0.93371063
+0.16888794
+0.45802802
+0.77514976
+0.112925306
+0.41139245
+0.028981315
+0.010327125
+0.11292531
+0.028981313
+0.5046636
+0.9150564
+0.99900043
+0.36475682
+0.4673551
+0.3367756
+0.81245816
+0.2155235
+0.12225255
+0.7285141
+0.03830839
+0.34610268
+0.6445701
+0.90572935
+0.46735507
+0.08494399
+0.9803462
+0.7005328
+0.028981308
+0.1502338
+0.55129915
+0.056962583
+0.26215878
+0.001
+0.21552338
+0.6818787
+0.38341117
+0.038308375
+0.6818787
+0.5046638
+0.7005328
+0.60726166
+0.81245816
+0.23417744
+0.3461027
+0.65389735
+0.06628969
+0.7098598
+0.32744846
+0.18754216
+0.6352431
+0.10359822
+0.94303775
+0.3367755
+0.7564956
+0.9150564
+0.89640224
+0.99900043
+0.2528317
+0.09427107
+0.635243
+0.5369992
+0.52984786
+0.54756886
+0.5422835
+0.43719596
+0.52363014
+0.47108513
+0.5279833
+0.4213391
+0.45305237
+0.41823047
+0.49129438
+0.4642455
+0.50652903
+0.53482056
+0.4664212
+0.4449682
+0.52300787
+0.5289151
+0.4384398
+0.45864865
+0.52207553
+0.4490107
+0.55969524
+0.48445427
+0.5267381
+0.5404183
+0.44869956
+0.5320225
+0.4654884
+0.566225
+0.45087644
+0.43128857
+0.42880148
+0.52425164
+0.5087055
+0.4176089
+0.54197407
+0.44652355
+0.46704352
+0.52798176
+0.4107687
+0.4654884
+0.42849013
+0.48010147
+0.47543806
+0.538551
+0.5115033
+0.53357875
+0.4390612
+0.41885254
+0.5000005
+0.45149782
+0.4567832
+0.5382421
+0.5540993
+0.5031086
+0.5453929
+0.55005723
+0.44590163
+0.43097773
+0.4483886
+0.42569262
+0.43470928
+0.41854125
+0.42165032
+0.46984157
+0.47699314
+0.5382414
+0.44901082
+0.44621223
+0.48974022
+0.5304696
+0.56062824
+0.5485018
+0.41854134
+0.49409282
+0.42786875
+0.5615612
+0.5506783
+0.50777215
+0.56124943
+0.5540982
+0.5357551
+0.43035617
+0.5099492
+0.4319103
+0.43159947
+0.42600358
+0.562494
+0.5174119
+0.43128875
+0.5609393
+0.45927057
+0.4493212
+0.49720109
+0.48134533
+0.4947147
+0.44963247
+0.45522898
+0.5397966
+0.4605139
+0.43097767
+0.53699964
+0.5435267
+0.5659129
+0.41885272
+0.44683474
+0.5335799
+0.55845106
+0.48258862
+0.4978235
+0.4340867
+0.4350199
+0.42817983
+0.4418594
+0.43999457
+0.52300787
+0.5500567
+0.43284288
+0.44621256
+0.45429567
+0.45243043
+0.55876267
+0.52829295
+0.41636503
+0.4542963
+0.5292259
+0.49720162
+0.4284908
+0.41667572
+0.4390618
+0.5429041
+107
+3210
diff --git a/Robust/src/Benchmarks/SSJava/EyeTracking/makefile b/Robust/src/Benchmarks/SSJava/EyeTracking/makefile
new file mode 100644 (file)
index 0000000..353e7db
--- /dev/null
@@ -0,0 +1,23 @@
+BUILDSCRIPT=../../../buildscript
+
+PROGRAM=LEA
+SOURCE_FILES=LEA.java
+
+BSFLAGS= -32bit -ssjava -mainclass $(PROGRAM)  -heapsize-mb 1000  -nooptimize -debug -garbagestats -ssjavadebug #-printlinenum #-joptimize
+
+default: $(PROGRAM)s.bin
+
+$(PROGRAM)s.bin: $(SOURCE_FILES) makefile
+       $(BUILDSCRIPT) $(BSFLAGS) -o $(PROGRAM) -builddir sing $(SOURCE_FILES) 
+
+clean:
+       rm -f  $(PROGRAM).bin
+       rm -fr sing
+       rm -f  *~
+       rm -f  *.dot
+       rm -f  *.png
+       rm -f  *.txt
+       rm -f  aliases.txt
+       rm -f  results*txt
+       rm -f *log
+