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