View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.demos.video.videosift;
31  
32  import java.awt.event.KeyAdapter;
33  import java.awt.event.KeyEvent;
34  import java.io.File;
35  import java.io.IOException;
36  import java.util.List;
37  
38  import javax.swing.JOptionPane;
39  import javax.swing.SwingUtilities;
40  
41  import org.openimaj.feature.DoubleFV;
42  import org.openimaj.feature.DoubleFVComparison;
43  import org.openimaj.image.FImage;
44  import org.openimaj.image.MBFImage;
45  import org.openimaj.image.colour.RGBColour;
46  import org.openimaj.image.processing.face.detection.CLMDetectedFace;
47  import org.openimaj.image.processing.face.feature.CLMShapeFeature;
48  import org.openimaj.image.processing.face.feature.comparison.FaceFVComparator;
49  import org.openimaj.image.processing.face.feature.comparison.FacialFeatureComparator;
50  import org.openimaj.image.processing.face.recognition.AnnotatorFaceRecogniser;
51  import org.openimaj.image.processing.face.tracking.clm.CLMFaceTracker;
52  import org.openimaj.image.typography.hershey.HersheyFont;
53  import org.openimaj.io.IOUtils;
54  import org.openimaj.math.geometry.point.Point2d;
55  import org.openimaj.ml.annotation.AnnotatedObject;
56  import org.openimaj.ml.annotation.ScoredAnnotation;
57  import org.openimaj.ml.annotation.basic.KNNAnnotator;
58  import org.openimaj.video.VideoDisplay;
59  import org.openimaj.video.VideoDisplayListener;
60  import org.openimaj.video.capture.VideoCapture;
61  
62  public class VideoFacialExpressionRecognition extends KeyAdapter implements VideoDisplayListener<MBFImage> {
63  	private VideoCapture capture;
64  	private VideoDisplay<MBFImage> videoFrame;
65  
66  	private AnnotatorFaceRecogniser<CLMDetectedFace, String> recogniser;
67  	private CLMFaceTracker engine;
68  	private FImage currentFrame;
69  
70  	public VideoFacialExpressionRecognition() throws Exception {
71  		capture = new VideoCapture(320, 240);
72  		engine = new CLMFaceTracker();
73  		engine.fpd = 120;
74  		// engine.fcheck = true;
75  
76  		videoFrame = VideoDisplay.createVideoDisplay(capture);
77  		videoFrame.addVideoListener(this);
78  		SwingUtilities.getRoot(videoFrame.getScreen()).addKeyListener(this);
79  
80  		final CLMShapeFeature.Extractor extractor = new
81  				CLMShapeFeature.Extractor();
82  		final FacialFeatureComparator<CLMShapeFeature> comparator = new
83  				FaceFVComparator<CLMShapeFeature, DoubleFV>(
84  						DoubleFVComparison.EUCLIDEAN);
85  
86  		final KNNAnnotator<CLMDetectedFace, String, CLMShapeFeature> knn = KNNAnnotator.create(extractor, comparator, 1,
87  				5f);
88  
89  		recogniser = AnnotatorFaceRecogniser.create(knn);
90  	}
91  
92  	@Override
93  	public synchronized void keyPressed(KeyEvent key) {
94  		if (key.getKeyCode() == KeyEvent.VK_SPACE) {
95  			this.videoFrame.togglePause();
96  		} else if (key.getKeyChar() == 'c') {
97  			// if (!this.videoFrame.isPaused())
98  			// this.videoFrame.togglePause();
99  
100 			final String person = JOptionPane.showInputDialog(this.videoFrame.getScreen(), "", "",
101 					JOptionPane.QUESTION_MESSAGE);
102 
103 			final List<CLMDetectedFace> faces = detectFaces();
104 			if (faces.size() == 1) {
105 				recogniser.train(new AnnotatedObject<CLMDetectedFace, String>(faces.get(0), person));
106 			} else {
107 				System.out.println("Wrong number of faces found");
108 			}
109 
110 			// this.videoFrame.togglePause();
111 		} else if (key.getKeyChar() == 'd') {
112 			engine.reset();
113 		}
114 		// else if (key.getKeyChar() == 'q') {
115 		// if (!this.videoFrame.isPaused())
116 		// this.videoFrame.togglePause();
117 		//
118 		// final List<CLMDetectedFace> faces = detectFaces();
119 		// if (faces.size() == 1) {
120 		// System.out.println("Looks like: " +
121 		// recogniser.annotate(faces.get(0)));
122 		// } else {
123 		// System.out.println("Wrong number of faces found");
124 		// }
125 		//
126 		// this.videoFrame.togglePause();
127 		// }
128 		else if (key.getKeyChar() == 's') {
129 			try {
130 				final File f = new File("rec.bin");
131 				f.delete();
132 				IOUtils.writeBinaryFull(f, this.recogniser);
133 			} catch (final IOException e) {
134 				e.printStackTrace();
135 			}
136 		} else if (key.getKeyChar() == 'l') {
137 			try {
138 				final File f = new File("rec.bin");
139 				this.recogniser = IOUtils.read(f);
140 			} catch (final IOException e) {
141 				// TODO Auto-generated catch block
142 				e.printStackTrace();
143 			}
144 		}
145 	}
146 
147 	private List<CLMDetectedFace> detectFaces() {
148 		return CLMDetectedFace.convert(engine.model.trackedFaces, currentFrame);
149 	}
150 
151 	@Override
152 	public void afterUpdate(VideoDisplay<MBFImage> display) {
153 		// do nothing
154 	}
155 
156 	@Override
157 	public synchronized void beforeUpdate(MBFImage frame) {
158 		this.currentFrame = frame.flatten();
159 		engine.track(frame);
160 		engine.drawModel(frame, true, true, true, true, true);
161 
162 		if (recogniser != null && recogniser.listPeople().size() >= 1) {
163 			for (final CLMDetectedFace f : detectFaces()) {
164 				final List<ScoredAnnotation<String>> name = recogniser.annotate(f);
165 
166 				if (name.size() > 0) {
167 					final Point2d r = f.getBounds().getTopLeft();
168 					frame.drawText(name.get(0).annotation, r, HersheyFont.ROMAN_SIMPLEX, 15, RGBColour.GREEN);
169 				}
170 			}
171 		}
172 	}
173 
174 	public static void main(String[] args) throws Exception {
175 		new VideoFacialExpressionRecognition();
176 	}
177 }