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}