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}