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}