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 */
030package org.openimaj.demos;
031
032import java.io.BufferedWriter;
033import java.io.DataInput;
034import java.io.DataOutput;
035import java.io.File;
036import java.io.FileWriter;
037import java.io.IOException;
038import java.util.ArrayList;
039import java.util.List;
040
041import org.apache.commons.io.IOUtils;
042import org.openimaj.image.FImage;
043import org.openimaj.image.ImageUtilities;
044import org.openimaj.image.processing.face.alignment.AffineAligner;
045import org.openimaj.image.processing.face.alignment.FaceAligner;
046import org.openimaj.image.processing.face.detection.DetectedFace;
047import org.openimaj.image.processing.face.detection.FaceDetector;
048import org.openimaj.image.processing.face.detection.keypoints.FKEFaceDetector;
049import org.openimaj.image.processing.face.detection.keypoints.KEDetectedFace;
050import org.openimaj.math.geometry.shape.Rectangle;
051import org.openimaj.util.function.Operation;
052import org.openimaj.util.parallel.Parallel;
053
054import scala.actors.threadpool.Arrays;
055
056public class FVFWDetectAlign {
057        static interface FDFactory {
058                FKEFaceDetector create();
059        }
060
061        @SuppressWarnings("unchecked")
062        private static void extractFaces(final File indir, final File outDir, final FDFactory factory,
063                        final FaceAligner<KEDetectedFace> aligner) throws IOException
064        {
065                final List<String> skipped = new ArrayList<String>();
066
067                Parallel.forEach(Arrays.asList(indir.listFiles()), new Operation<File>() {
068
069                        @Override
070                        public void perform(File dir) {
071                                try {
072                                        if (!dir.isDirectory())
073                                                return;
074
075                                        final FKEFaceDetector detector = factory.create();
076
077                                        for (final File imgfile : dir.listFiles()) {
078                                                if (!imgfile.getName().endsWith(".jpg"))
079                                                        continue;
080
081                                                System.out.println(imgfile);
082                                                final File outfile = new File(outDir, imgfile.getAbsolutePath().replace(indir.getAbsolutePath(),
083                                                                ""));
084                                                outfile.getParentFile().mkdirs();
085
086                                                final FImage aligned = extractAndAlignFace(ImageUtilities.readF(imgfile), detector, aligner);
087
088                                                if (aligned == null) {
089                                                        synchronized (skipped) {
090                                                                skipped.add(imgfile.toString());
091                                                        }
092                                                } else {
093                                                        ImageUtilities.write(aligned, outfile);
094                                                }
095                                        }
096                                } catch (final Exception e) {
097                                        e.printStackTrace();
098                                        System.err.println(e);
099                                }
100                        }
101                });
102
103                final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outDir, "skipped.txt")));
104                IOUtils.writeLines(skipped, "\n", writer);
105                writer.close();
106        }
107
108        private static FImage
109                        extractAndAlignFace(FImage img, FKEFaceDetector detector, FaceAligner<KEDetectedFace> aligner)
110        {
111                final List<KEDetectedFace> faces = detector.detectFaces(img);
112
113                if (faces.size() == 1)
114                        return aligner.align(faces.get(0));
115
116                return null;
117        }
118
119        /**
120         * @param args
121         * @throws IOException
122         */
123        public static void main(String[] args) throws IOException {
124                final FDFactory factory = new FDFactory() {
125                        @Override
126                        public FKEFaceDetector create() {
127                                final FaceDetector<DetectedFace, FImage> inner = new FaceDetector<DetectedFace, FImage>() {
128                                        @Override
129                                        public void readBinary(DataInput in) throws IOException {
130                                                // do nothing
131                                        }
132
133                                        @Override
134                                        public byte[] binaryHeader() {
135                                                return null;
136                                        }
137
138                                        @Override
139                                        public void writeBinary(DataOutput out) throws IOException {
140                                                // do nothing
141                                        }
142
143                                        @Override
144                                        public List<DetectedFace> detectFaces(FImage image) {
145                                                final List<DetectedFace> faces = new ArrayList<DetectedFace>();
146
147                                                final int dw = Math.round(image.width / 2.2f);
148                                                final int dh = Math.round(image.height / 2.2f);
149                                                final int x = (image.width - dw) / 2;
150                                                final int y = (image.height - dh) / 2;
151                                                final Rectangle bounds = new Rectangle(x, y, dw, dh);
152
153                                                faces.add(new DetectedFace(bounds, image.extractROI(bounds), 1f));
154
155                                                return faces;
156                                        }
157                                };
158
159                                return new FKEFaceDetector(inner, 1.5f);
160                        }
161                };
162
163                final AffineAligner aligner = new AffineAligner(125, 160, 0.1f);
164
165                extractFaces(new File("/Volumes/Raid/face_databases/lfw"), new File(
166                                "/Volumes/Raid/face_databases/lfw-centre-affine/"), factory, aligner);
167        }
168}