001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/** 031 * 032 */ 033package org.openimaj.demos.video.utils; 034 035import java.awt.GridBagConstraints; 036import java.awt.GridBagLayout; 037import java.awt.event.ActionEvent; 038import java.awt.event.ActionListener; 039import java.io.IOException; 040import java.util.List; 041 042import javax.swing.BorderFactory; 043import javax.swing.JCheckBox; 044import javax.swing.JPanel; 045 046import org.openimaj.demos.faces.Mustache; 047import org.openimaj.image.MBFImage; 048import org.openimaj.image.colour.RGBColour; 049import org.openimaj.image.colour.Transforms; 050import org.openimaj.image.processing.edges.CannyEdgeDetector; 051import org.openimaj.image.processing.face.detection.DetectedFace; 052import org.openimaj.image.processing.face.detection.HaarCascadeDetector; 053import org.openimaj.image.processing.face.detection.keypoints.FKEFaceDetector; 054import org.openimaj.image.processing.face.detection.keypoints.FacialKeypoint; 055import org.openimaj.image.processing.face.detection.keypoints.KEDetectedFace; 056import org.openimaj.image.renderer.MBFImageRenderer; 057import org.openimaj.math.geometry.point.Point2d; 058import org.openimaj.math.geometry.shape.Shape; 059import org.openimaj.video.VideoDisplay; 060import org.openimaj.video.VideoDisplayListener; 061 062/** 063 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 064 * 065 * @created 28 Sep 2011 066 */ 067public class ProcessingPanel extends JPanel 068 implements VideoDisplayListener<MBFImage> 069{ 070 /** */ 071 private static final long serialVersionUID = 1L; 072 073 private boolean edgeDetect = false; 074 private boolean faceDetect = false; 075 private boolean faceKPDetect = false; 076 private boolean moustache = false; 077 078 private final FKEFaceDetector fkp; 079 080 private final HaarCascadeDetector d; 081 082 /** 083 * 084 */ 085 public ProcessingPanel() 086 { 087 this.d = new HaarCascadeDetector(100); 088 this.fkp = new FKEFaceDetector( 089 HaarCascadeDetector.BuiltInCascade.frontalface_alt.load()); 090 this.init(); 091 } 092 093 /** 094 * 095 */ 096 private void init() 097 { 098 this.setLayout(new GridBagLayout()); 099 this.setBorder(BorderFactory.createTitledBorder("Processing")); 100 101 final GridBagConstraints gbc = new GridBagConstraints(); 102 gbc.gridx = gbc.gridy = 0; 103 gbc.fill = GridBagConstraints.HORIZONTAL; 104 gbc.weightx = 1; 105 gbc.weighty = 0; 106 gbc.gridwidth = 1; 107 108 // ----------------------------------------------------- 109 final JCheckBox edgeDetectButton = new JCheckBox("Edge Detect", this.edgeDetect); 110 edgeDetectButton.addActionListener(new ActionListener() 111 { 112 @Override 113 public void actionPerformed(final ActionEvent e) 114 { 115 ProcessingPanel.this.edgeDetect = edgeDetectButton.isSelected(); 116 } 117 }); 118 gbc.gridy++; 119 this.add(edgeDetectButton, gbc); 120 121 // ----------------------------------------------------- 122 final JCheckBox faceDetectorButton = new JCheckBox("Face Detection", this.faceDetect); 123 faceDetectorButton.addActionListener(new ActionListener() 124 { 125 @Override 126 public void actionPerformed(final ActionEvent e) 127 { 128 ProcessingPanel.this.faceDetect = faceDetectorButton.isSelected(); 129 } 130 }); 131 gbc.gridy++; 132 this.add(faceDetectorButton, gbc); 133 134 // ----------------------------------------------------- 135 final JCheckBox faceKPDetectorButton = new JCheckBox("Facial Keypoint Detection", this.faceKPDetect); 136 faceKPDetectorButton.addActionListener(new ActionListener() 137 { 138 @Override 139 public void actionPerformed(final ActionEvent e) 140 { 141 ProcessingPanel.this.faceKPDetect = faceKPDetectorButton.isSelected(); 142 } 143 }); 144 gbc.gridy++; 145 this.add(faceKPDetectorButton, gbc); 146 147 // ----------------------------------------------------- 148 final JCheckBox moustacheButton = new JCheckBox("Add Moustaches", this.moustache); 149 moustacheButton.addActionListener(new ActionListener() 150 { 151 @Override 152 public void actionPerformed(final ActionEvent e) 153 { 154 ProcessingPanel.this.moustache = moustacheButton.isSelected(); 155 } 156 }); 157 gbc.gridy++; 158 this.add(moustacheButton, gbc); 159 160 } 161 162 /** 163 * {@inheritDoc} 164 * 165 * @see org.openimaj.video.VideoDisplayListener#afterUpdate(org.openimaj.video.VideoDisplay) 166 */ 167 @Override 168 public void afterUpdate(final VideoDisplay<MBFImage> display) 169 { 170 } 171 172 /** 173 * {@inheritDoc} 174 * 175 * @see org.openimaj.video.VideoDisplayListener#beforeUpdate(org.openimaj.image.Image) 176 */ 177 @Override 178 public void beforeUpdate(final MBFImage frame) 179 { 180 if (this.edgeDetect) 181 frame.processInplace(new CannyEdgeDetector()); 182 183 if (this.faceDetect) 184 { 185 final List<DetectedFace> faces = this.d.detectFaces( 186 Transforms.calculateIntensityNTSC(frame)); 187 188 for (final DetectedFace face : faces) 189 { 190 final Shape transBounds = face.getBounds(); 191 final MBFImageRenderer renderer = frame.createRenderer(); 192 renderer.drawPolygon(transBounds.asPolygon(), RGBColour.RED); 193 } 194 } 195 196 if (this.faceKPDetect) 197 { 198 final List<KEDetectedFace> faces = this.fkp.detectFaces( 199 Transforms.calculateIntensityNTSC(frame)); 200 201 for (final KEDetectedFace face : faces) 202 { 203 final Shape transBounds = face.getBounds(); 204 final MBFImageRenderer renderer = frame.createRenderer(); 205 renderer.drawPolygon(transBounds.asPolygon(), RGBColour.RED); 206 207 for (final FacialKeypoint kp : face.getKeypoints()) 208 { 209 final Point2d pt = kp.position.clone(); 210 pt.translate((float) transBounds.minX(), (float) transBounds.minY()); 211 renderer.drawPoint(pt, RGBColour.GREEN, 3); 212 } 213 } 214 } 215 216 if (this.moustache) 217 try { 218 frame.internalAssign(new Mustache().addMustaches(frame)); 219 } catch (final IOException e) { 220 e.printStackTrace(); 221 } 222 } 223}