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.tools.faces.recognition.options; 031 032import org.kohsuke.args4j.CmdLineOptionsProvider; 033import org.kohsuke.args4j.Option; 034import org.kohsuke.args4j.ProxyOptionHandler; 035import org.openimaj.image.FImage; 036import org.openimaj.image.processing.face.alignment.AffineAligner; 037import org.openimaj.image.processing.face.alignment.CLMAligner; 038import org.openimaj.image.processing.face.alignment.FaceAligner; 039import org.openimaj.image.processing.face.alignment.IdentityAligner; 040import org.openimaj.image.processing.face.alignment.MeshWarpAligner; 041import org.openimaj.image.processing.face.alignment.RotateScaleAligner; 042import org.openimaj.image.processing.face.alignment.ScalingAligner; 043import org.openimaj.image.processing.face.detection.CLMDetectedFace; 044import org.openimaj.image.processing.face.detection.CLMFaceDetector; 045import org.openimaj.image.processing.face.detection.DetectedFace; 046import org.openimaj.image.processing.face.detection.FaceDetector; 047import org.openimaj.image.processing.face.detection.keypoints.FKEFaceDetector; 048import org.openimaj.image.processing.face.detection.keypoints.KEDetectedFace; 049import org.openimaj.tools.faces.recognition.options.FaceDetectors.AnyBasicFImageDetector; 050import org.openimaj.tools.faces.recognition.options.FaceDetectors.FaceDetectorProvider; 051 052/** 053 * Face aligners configuration for the tools. 054 * 055 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 056 */ 057public class Aligners { 058 /** 059 * Interface for configuration objects that can provide a compatible aligner 060 * and detector pair. 061 * 062 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 063 * 064 * @param <FACE> 065 * type of {@link DetectedFace} 066 * 067 */ 068 public interface AlignerDetectorProvider<FACE extends DetectedFace> { 069 /** 070 * @return the aligner 071 */ 072 public FaceAligner<FACE> getAligner(); 073 074 /** 075 * @return the detector 076 */ 077 public FaceDetector<FACE, FImage> getDetector(); 078 } 079 080 /** 081 * All types of aligner 082 * 083 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 084 * 085 */ 086 public enum AnyAligner implements CmdLineOptionsProvider { 087 /** 088 * Identity aligner 089 * 090 * @see IdentityAligner 091 */ 092 Identity { 093 @Override 094 public AlignerDetectorProvider<?> getOptions() { 095 return new Identity(); 096 } 097 }, 098 /** 099 * Scaling aligner 100 * 101 * @see ScalingAligner 102 */ 103 Scaling { 104 @Override 105 public AlignerDetectorProvider<?> getOptions() { 106 return new Scaling(); 107 } 108 }, 109 /** 110 * Affine aligner 111 * 112 * @see AffineAligner 113 */ 114 Affine { 115 @Override 116 public AlignerDetectorProvider<?> getOptions() { 117 return new Affine(); 118 } 119 }, 120 /** 121 * MeshWarp aligner 122 * 123 * @see MeshWarpAligner 124 */ 125 MeshWarp { 126 @Override 127 public AlignerDetectorProvider<?> getOptions() { 128 return new MeshWarp(); 129 } 130 }, 131 /** 132 * Rotate Scale aligner 133 * 134 * @see RotateScaleAligner 135 */ 136 RotateScale { 137 @Override 138 public AlignerDetectorProvider<?> getOptions() { 139 return new RotateScale(); 140 } 141 }, 142 /** 143 * CLM Aligner 144 * 145 * @see CLMAligner 146 */ 147 CLM { 148 @Override 149 public AlignerDetectorProvider<?> getOptions() { 150 return new CLM(); 151 } 152 }; 153 154 @Override 155 public abstract AlignerDetectorProvider<?> getOptions(); 156 } 157 158 private static class Identity implements AlignerDetectorProvider<DetectedFace> { 159 @Option(name = "--detector", usage = "Face detector", required = true, handler = ProxyOptionHandler.class) 160 AnyBasicFImageDetector detector; 161 FaceDetectorProvider<DetectedFace, FImage> detectorOp; 162 163 @Override 164 public FaceAligner<DetectedFace> getAligner() { 165 return new IdentityAligner<DetectedFace>(); 166 } 167 168 @Override 169 public FaceDetector<DetectedFace, FImage> getDetector() { 170 return detectorOp.getDetector(); 171 } 172 } 173 174 private static class Scaling implements AlignerDetectorProvider<DetectedFace> { 175 @Option(name = "--detector", usage = "Face detector", required = true, handler = ProxyOptionHandler.class) 176 AnyBasicFImageDetector detector; 177 FaceDetectorProvider<DetectedFace, FImage> detectorOp; 178 179 @Option(name = "--width", usage = "Aligner patch output width", required = false) 180 int width = 100; 181 182 @Option(name = "--height", usage = "Aligner patch output height", required = false) 183 int height = 100; 184 185 @Override 186 public FaceAligner<DetectedFace> getAligner() { 187 return new ScalingAligner<DetectedFace>(width, height); 188 } 189 190 @Override 191 public FaceDetector<DetectedFace, FImage> getDetector() { 192 return detectorOp.getDetector(); 193 } 194 } 195 196 private static class Affine implements AlignerDetectorProvider<KEDetectedFace> { 197 @Option(name = "--detector", usage = "Face detector", required = true, handler = ProxyOptionHandler.class) 198 AnyBasicFImageDetector detector; 199 FaceDetectorProvider<DetectedFace, FImage> detectorOp; 200 201 @Override 202 public FaceAligner<KEDetectedFace> getAligner() { 203 return new AffineAligner(); 204 } 205 206 @Override 207 public FaceDetector<KEDetectedFace, FImage> getDetector() { 208 return new FKEFaceDetector(detectorOp.getDetector()); 209 } 210 } 211 212 private static class MeshWarp implements AlignerDetectorProvider<KEDetectedFace> { 213 @Option(name = "--detector", usage = "Face detector", required = true, handler = ProxyOptionHandler.class) 214 AnyBasicFImageDetector detector; 215 FaceDetectorProvider<DetectedFace, FImage> detectorOp; 216 217 @Override 218 public FaceAligner<KEDetectedFace> getAligner() { 219 return new MeshWarpAligner(); 220 } 221 222 @Override 223 public FaceDetector<KEDetectedFace, FImage> getDetector() { 224 return new FKEFaceDetector(detectorOp.getDetector()); 225 } 226 } 227 228 private static class RotateScale implements AlignerDetectorProvider<KEDetectedFace> { 229 @Option(name = "--detector", usage = "Face detector", required = true, handler = ProxyOptionHandler.class) 230 AnyBasicFImageDetector detector; 231 FaceDetectorProvider<DetectedFace, FImage> detectorOp; 232 233 @Override 234 public FaceAligner<KEDetectedFace> getAligner() { 235 return new RotateScaleAligner(); 236 } 237 238 @Override 239 public FaceDetector<KEDetectedFace, FImage> getDetector() { 240 return new FKEFaceDetector(detectorOp.getDetector()); 241 } 242 } 243 244 private static class CLM implements AlignerDetectorProvider<CLMDetectedFace> { 245 @Option(name = "--size", usage = "Size of aligned image", required = false) 246 int size = 100; 247 248 @Override 249 public FaceAligner<CLMDetectedFace> getAligner() { 250 return new CLMAligner(size); 251 } 252 253 @Override 254 public FaceDetector<CLMDetectedFace, FImage> getDetector() { 255 return new CLMFaceDetector(); 256 } 257 } 258}