1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package android.hardware.camera2.params; 19 20 import android.graphics.Point; 21 import android.graphics.Rect; 22 import android.hardware.camera2.CameraCharacteristics; 23 import android.hardware.camera2.CameraMetadata; 24 import android.hardware.camera2.CaptureResult; 25 26 /** 27 * Describes a face detected in an image. 28 */ 29 public final class Face { 30 31 /** 32 * The ID is {@code -1} when the optional set of fields is unsupported. 33 * 34 * @see #getId() 35 */ 36 public static final int ID_UNSUPPORTED = -1; 37 38 /** 39 * The minimum possible value for the confidence level. 40 * 41 * @see #getScore() 42 */ 43 public static final int SCORE_MIN = 1; 44 45 /** 46 * The maximum possible value for the confidence level. 47 * 48 * @see #getScore() 49 */ 50 public static final int SCORE_MAX = 100; 51 52 private final Rect mBounds; 53 private final int mScore; 54 private final int mId; 55 private final Point mLeftEye; 56 private final Point mRightEye; 57 private final Point mMouth; 58 59 /** 60 * Create a new face with all fields set. 61 * 62 * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional. 63 * They are only required when the {@link CaptureResult} reports that the value of key 64 * {@link CaptureResult#STATISTICS_FACE_DETECT_MODE} is 65 * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_FULL}. 66 * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and 67 * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition, 68 * rightEyePosition, and mouthPosition may be independently null or not-null.</p> 69 * 70 * @param bounds Bounds of the face. 71 * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}. 72 * @param id A unique ID per face visible to the tracker. 73 * @param leftEyePosition The position of the left eye. 74 * @param rightEyePosition The position of the right eye. 75 * @param mouthPosition The position of the mouth. 76 * 77 * @throws IllegalArgumentException 78 * if bounds is {@code null}, 79 * or if the confidence is not in the range of 80 * {@value #SCORE_MIN}-{@value #SCORE_MAX}, 81 * or if id is {@value #ID_UNSUPPORTED} and 82 * leftEyePosition/rightEyePosition/mouthPosition aren't all null, 83 * or else if id is negative. 84 * 85 * @hide 86 */ Face(Rect bounds, int score, int id, Point leftEyePosition, Point rightEyePosition, Point mouthPosition)87 public Face(Rect bounds, int score, int id, 88 Point leftEyePosition, Point rightEyePosition, Point mouthPosition) { 89 checkNotNull("bounds", bounds); 90 if (score < SCORE_MIN || score > SCORE_MAX) { 91 throw new IllegalArgumentException("Confidence out of range"); 92 } else if (id < 0 && id != ID_UNSUPPORTED) { 93 throw new IllegalArgumentException("Id out of range"); 94 } 95 if (id == ID_UNSUPPORTED) { 96 checkNull("leftEyePosition", leftEyePosition); 97 checkNull("rightEyePosition", rightEyePosition); 98 checkNull("mouthPosition", mouthPosition); 99 } 100 101 mBounds = bounds; 102 mScore = score; 103 mId = id; 104 mLeftEye = leftEyePosition; 105 mRightEye = rightEyePosition; 106 mMouth = mouthPosition; 107 } 108 109 /** 110 * Create a new face without the optional fields. 111 * 112 * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional. 113 * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and 114 * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition, 115 * rightEyePosition, and mouthPosition may be independently null or not-null. When devices 116 * report the value of key {@link CaptureResult#STATISTICS_FACE_DETECT_MODE} as 117 * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_SIMPLE} in {@link CaptureResult}, 118 * the face id of each face is expected to be {@value #ID_UNSUPPORTED}, the leftEyePosition, 119 * rightEyePosition, and mouthPositions are expected to be {@code null} for each face.</p> 120 * 121 * @param bounds Bounds of the face. 122 * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}. 123 * 124 * @throws IllegalArgumentException 125 * if bounds is {@code null}, 126 * or if the confidence is not in the range of 127 * {@value #SCORE_MIN}-{@value #SCORE_MAX}. 128 * 129 * @hide 130 */ Face(Rect bounds, int score)131 public Face(Rect bounds, int score) { 132 this(bounds, score, ID_UNSUPPORTED, 133 /*leftEyePosition*/null, /*rightEyePosition*/null, /*mouthPosition*/null); 134 } 135 136 /** 137 * Bounds of the face. 138 * 139 * <p>A rectangle relative to the sensor's 140 * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0) 141 * representing the top-left corner of the active array rectangle.</p> 142 * 143 * <p>There is no constraints on the the Rectangle value other than it 144 * is not-{@code null}.</p> 145 */ getBounds()146 public Rect getBounds() { 147 return mBounds; 148 } 149 150 /** 151 * The confidence level for the detection of the face. 152 * 153 * <p>The range is {@value #SCORE_MIN} to {@value #SCORE_MAX}. 154 * {@value #SCORE_MAX} is the highest confidence.</p> 155 * 156 * <p>Depending on the device, even very low-confidence faces may be 157 * listed, so applications should filter out faces with low confidence, 158 * depending on the use case. For a typical point-and-shoot camera 159 * application that wishes to display rectangles around detected faces, 160 * filtering out faces with confidence less than half of {@value #SCORE_MAX} 161 * is recommended.</p> 162 * 163 * @see #SCORE_MAX 164 * @see #SCORE_MIN 165 */ getScore()166 public int getScore() { 167 return mScore; 168 } 169 170 /** 171 * An unique id per face while the face is visible to the tracker. 172 * 173 * <p> 174 * If the face leaves the field-of-view and comes back, it will get a new 175 * id.</p> 176 * 177 * <p>This is an optional field, may not be supported on all devices. 178 * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and 179 * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition, 180 * rightEyePosition, and mouthPosition may be independently null or not-null. When devices 181 * report the value of key {@link CaptureResult#STATISTICS_FACE_DETECT_MODE} as 182 * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_SIMPLE} in {@link CaptureResult}, 183 * the face id of each face is expected to be {@value #ID_UNSUPPORTED}.</p> 184 * 185 * <p>This value will either be {@value #ID_UNSUPPORTED} or 186 * otherwise greater than {@code 0}.</p> 187 * 188 * @see #ID_UNSUPPORTED 189 */ getId()190 public int getId() { 191 return mId; 192 } 193 194 /** 195 * The coordinates of the center of the left eye. 196 * 197 * <p>The coordinates are in 198 * the same space as the ones for {@link #getBounds}. This is an 199 * optional field, may not be supported on all devices. If not 200 * supported, the value will always be set to null. 201 * This value will always be null only if {@link #getId()} returns 202 * {@value #ID_UNSUPPORTED}.</p> 203 * 204 * @return The left eye position, or {@code null} if unknown. 205 */ getLeftEyePosition()206 public Point getLeftEyePosition() { 207 return mLeftEye; 208 } 209 210 /** 211 * The coordinates of the center of the right eye. 212 * 213 * <p>The coordinates are 214 * in the same space as the ones for {@link #getBounds}.This is an 215 * optional field, may not be supported on all devices. If not 216 * supported, the value will always be set to null. 217 * This value will always be null only if {@link #getId()} returns 218 * {@value #ID_UNSUPPORTED}.</p> 219 * 220 * @return The right eye position, or {@code null} if unknown. 221 */ getRightEyePosition()222 public Point getRightEyePosition() { 223 return mRightEye; 224 } 225 226 /** 227 * The coordinates of the center of the mouth. 228 * 229 * <p>The coordinates are in 230 * the same space as the ones for {@link #getBounds}. This is an optional 231 * field, may not be supported on all devices. If not 232 * supported, the value will always be set to null. 233 * This value will always be null only if {@link #getId()} returns 234 * {@value #ID_UNSUPPORTED}.</p> 235 * </p> 236 * 237 * @return The mouth position, or {@code null} if unknown. 238 */ getMouthPosition()239 public Point getMouthPosition() { 240 return mMouth; 241 } 242 243 /** 244 * Represent the Face as a string for debugging purposes. 245 */ 246 @Override toString()247 public String toString() { 248 return String.format("{ bounds: %s, score: %s, id: %d, " + 249 "leftEyePosition: %s, rightEyePosition: %s, mouthPosition: %s }", 250 mBounds, mScore, mId, mLeftEye, mRightEye, mMouth); 251 } 252 checkNotNull(String name, Object obj)253 private static void checkNotNull(String name, Object obj) { 254 if (obj == null) { 255 throw new IllegalArgumentException(name + " was required, but it was null"); 256 } 257 } 258 checkNull(String name, Object obj)259 private static void checkNull(String name, Object obj) { 260 if (obj != null) { 261 throw new IllegalArgumentException(name + " was required to be null, but it wasn't"); 262 } 263 } 264 } 265