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.image.processing.face.detection.keypoints; 031 032import java.io.DataInput; 033import java.io.DataOutput; 034import java.io.IOException; 035 036import org.openimaj.io.ReadWriteableBinary; 037import org.openimaj.math.geometry.point.Point2d; 038import org.openimaj.math.geometry.point.Point2dImpl; 039 040import Jama.Matrix; 041 042/** 043 * A {@link FacialKeypoint} represents a keypoint on a face. Keypoints 044 * are representative points found on all faces. 045 * <p> 046 * Keypoint types are based on Mark Everingham's 047 * <a href="http://www.robots.ox.ac.uk/~vgg/research/nface/">Oxford VGG 048 * Baseline Face Processing Code</a> 049 * 050 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 051 */ 052public class FacialKeypoint implements ReadWriteableBinary { 053 /** 054 * Types/locations of {@link FacialKeypoint}. 055 * 056 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 057 */ 058 public static enum FacialKeypointType { 059 /** 060 * Left of the left eye 061 */ 062 EYE_LEFT_LEFT, 063 /** 064 * Right of the left eye 065 */ 066 EYE_LEFT_RIGHT, 067 /** 068 * Left of the right eye 069 */ 070 EYE_RIGHT_LEFT, 071 /** 072 * Right of the left eye 073 */ 074 EYE_RIGHT_RIGHT, 075 /** 076 * Left-bottom of the nose 077 */ 078 NOSE_LEFT, 079 /** 080 * Bottom-middle of the nose 081 */ 082 NOSE_MIDDLE, 083 /** 084 * Bottom-right of the nose 085 */ 086 NOSE_RIGHT, 087 /** 088 * Left corner of the mouth 089 */ 090 MOUTH_LEFT, 091 /** 092 * Right corner of the mouth 093 */ 094 MOUTH_RIGHT, 095 /** 096 * Centre of the left eye 097 */ 098 EYE_LEFT_CENTER, 099 /** 100 * Centre of the right eye 101 */ 102 EYE_RIGHT_CENTER, 103 /** 104 * Bridge of the nose 105 */ 106 NOSE_BRIDGE, 107 /** 108 * Centre of the mouth 109 */ 110 MOUTH_CENTER 111 ; 112 113 /** 114 * Get the {@link FacialKeypointType} at the specified ordinal 115 * @param ordinal the ordinal 116 * @return the corresponding {@link FacialKeypointType} 117 */ 118 public static FacialKeypointType valueOf(int ordinal) { 119 return FacialKeypointType.values()[ordinal]; 120 } 121 } 122 123 /** 124 * The type of facial keypoint 125 */ 126 public FacialKeypointType type; 127 128 /** 129 * The position of the keypoint in the image 130 */ 131 public Point2dImpl position; 132 133 /** 134 * Default constructor. Sets type to {@link FacialKeypointType#EYE_LEFT_CENTER} 135 * and position to the origin. 136 */ 137 public FacialKeypoint() { 138 this.type = FacialKeypointType.EYE_LEFT_CENTER; 139 position = new Point2dImpl(0, 0); 140 } 141 142 /** 143 * Construct a FacialKeypoint at the origin with the specified type. 144 * @param type the type of facial keypoint 145 */ 146 public FacialKeypoint(FacialKeypointType type) { 147 this.type = type; 148 position = new Point2dImpl(0, 0); 149 } 150 151 /** 152 * Construct a FacialKeypoint with the specified type and position. 153 * @param type the type of facial keypoint 154 * @param pt the position in the image of the facial keypoint 155 */ 156 public FacialKeypoint(FacialKeypointType type, Point2d pt) { 157 this.type = type; 158 position = new Point2dImpl(pt); 159 } 160 161 protected void updatePosition(Matrix transform) { 162 position = position.transform(transform); 163 } 164 165 protected static void updateImagePosition(FacialKeypoint[] kpts, Matrix transform) { 166 for (FacialKeypoint k : kpts) k.updatePosition(transform); 167 } 168 169 /** 170 * Search the given points for the a keypoint with the 171 * specified type and return it. 172 * 173 * @param pts the points to search 174 * @param type the type of facial keypoint 175 * @return the selected keypoint; or null if not found 176 */ 177 public static FacialKeypoint getKeypoint(FacialKeypoint[] pts, FacialKeypointType type) { 178 for (FacialKeypoint fk : pts) { 179 if (fk.type == type) 180 return fk; 181 } 182 return null; 183 } 184 185 @Override 186 public void readBinary(DataInput in) throws IOException { 187 type = FacialKeypointType.valueOf(in.readUTF()); 188 position.readBinary(in); 189 } 190 191 @Override 192 public byte[] binaryHeader() { 193 return this.getClass().getName().getBytes(); 194 } 195 196 @Override 197 public void writeBinary(DataOutput out) throws IOException { 198 out.writeUTF(type.name()); 199 position.writeBinary(out); 200 } 201}