2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Runtime.InteropServices;
19 using System.Threading.Tasks;
20 using InteropFace = Interop.MediaVision.Face;
22 namespace Tizen.Multimedia.Vision
25 /// Provides the ability to recognize faces, face expressions, and eye condition on image sources.
27 /// <since_tizen> 3 </since_tizen>
28 public static class FaceRecognizer
32 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/>.
34 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
35 /// <param name="recognitionModel">The <see cref="FaceRecognitionConfiguration"/> to be used for recognition.</param>
36 /// <returns>A task that represents the asynchronous recognition operation.</returns>
37 /// <exception cref="ArgumentNullException">
38 /// <paramref name="source"/> is null.<br/>
40 /// <paramref name="recognitionModel"/> is null.
42 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
43 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
44 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
45 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
46 /// <since_tizen> 3 </since_tizen>
47 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
48 FaceRecognitionModel recognitionModel)
50 return await InvokeRecognizeAsync(source, recognitionModel, null, null);
54 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/> and a bounding box.
56 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
57 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
58 /// <param name="bound">Rectangular box bounding face image on the source.</param>
59 /// <returns>A task that represents the asynchronous recognition operation.</returns>
60 /// <exception cref="ArgumentNullException">
61 /// <paramref name="source"/> is null.<br/>
63 /// <paramref name="recognitionModel"/> is null.
65 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
66 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
67 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
68 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
69 /// <since_tizen> 3 </since_tizen>
70 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
71 FaceRecognitionModel recognitionModel, Rectangle bound)
73 return await InvokeRecognizeAsync(source, recognitionModel, bound, null);
77 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/> and <see cref="FaceRecognitionConfiguration"/>.
79 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
80 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
81 /// <param name="config">The configuration used for recognition. This value can be null.</param>
82 /// <returns>A task that represents the asynchronous recognition operation.</returns>
83 /// <exception cref="ArgumentNullException">
84 /// <paramref name="source"/> is null.<br/>
86 /// <paramref name="recognitionModel"/> is null.
88 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
89 /// <exception cref="ObjectDisposedException">
90 /// <paramref name="source"/> has already been disposed of.<br/>
92 /// <paramref name="config"/> has already been disposed of.
94 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
95 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
96 /// <since_tizen> 3 </since_tizen>
97 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
98 FaceRecognitionModel recognitionModel, FaceRecognitionConfiguration config)
100 return await InvokeRecognizeAsync(source, recognitionModel, null, config);
104 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/>, <see cref="FaceRecognitionConfiguration"/>
105 /// and a bounding box.
107 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
108 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
109 /// <param name="bound">Rectangular box bounding face image on the source.</param>
110 /// <param name="config">The <see cref="FaceRecognitionConfiguration"/> used for recognition. This value can be null.</param>
111 /// <returns>A task that represents the asynchronous recognition operation.</returns>
112 /// <exception cref="ArgumentNullException">
113 /// <paramref name="source"/> is null.<br/>
115 /// <paramref name="recognitionModel"/> is null.
117 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
118 /// <exception cref="ObjectDisposedException">
119 /// <paramref name="source"/> has already been disposed of.<br/>
121 /// <paramref name="config"/> has already been disposed of.
123 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
124 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
125 /// <since_tizen> 3 </since_tizen>
126 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
127 FaceRecognitionModel recognitionModel, Rectangle bound, FaceRecognitionConfiguration config)
129 return await InvokeRecognizeAsync(source, recognitionModel, bound, config);
132 private static MediaVisionError InvokeRecognize(IntPtr sourceHandle, IntPtr modelHandle,
133 IntPtr configHandle, InteropFace.RecognizedCallback cb, Rectangle? area)
137 return InteropFace.Recognize(sourceHandle, modelHandle, configHandle, IntPtr.Zero, cb);
140 var rect = area.Value.ToMarshalable();
141 return InteropFace.Recognize(sourceHandle, modelHandle, configHandle, ref rect, cb);
144 private static async Task<FaceRecognitionResult> InvokeRecognizeAsync(MediaVisionSource source,
145 FaceRecognitionModel recognitionModel, Rectangle? area,
146 FaceRecognitionConfiguration config)
150 throw new ArgumentNullException(nameof(source));
152 if (recognitionModel == null)
154 throw new ArgumentNullException(nameof(recognitionModel));
157 TaskCompletionSource<FaceRecognitionResult> tcs = new TaskCompletionSource<FaceRecognitionResult>();
159 using (var cb = ObjectKeeper.Get(GetRecognizedCallback(tcs)))
161 InvokeRecognize(source.Handle, recognitionModel.Handle, EngineConfiguration.GetHandle(config),
162 cb.Target, area).Validate("Failed to perform face recognition.");
164 return await tcs.Task;
168 private static FaceRecognitionResult CreateRecognitionResult(
169 IntPtr faceLocationPtr, IntPtr faceLabelPtr, double confidence)
172 if (faceLabelPtr != IntPtr.Zero)
174 faceLabel = Marshal.ReadInt32(faceLabelPtr);
177 Rectangle? faceLocation = null;
178 if (faceLocationPtr != IntPtr.Zero)
180 var area = Marshal.PtrToStructure<global::Interop.MediaVision.Rectangle>(faceLocationPtr);
181 faceLocation = area.ToApiStruct();
184 return new FaceRecognitionResult(faceLabelPtr != IntPtr.Zero, confidence, faceLabel, faceLocation);
187 private static InteropFace.RecognizedCallback GetRecognizedCallback(
188 TaskCompletionSource<FaceRecognitionResult> tcs)
190 return (IntPtr sourceHandle, IntPtr recognitionModelHandle,
191 IntPtr engineCfgHandle, IntPtr faceLocationPtr, IntPtr faceLabelPtr, double confidence, IntPtr _) =>
195 if (!tcs.TrySetResult(CreateRecognitionResult(faceLocationPtr, faceLabelPtr, confidence)))
197 Log.Error(MediaVisionLog.Tag, "Failed to set result");
202 MultimediaLog.Error(MediaVisionLog.Tag, "Setting recognition result failed.", e);
203 tcs.TrySetException(e);
209 /// Determines eye-blink condition on media source.
211 /// <param name="source">The source of the media to recognize eye-blink condition for.</param>
212 /// <param name="bound">The bounding the face at the source.</param>
213 /// <returns>A task that represents the asynchronous recognition operation.</returns>
214 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
215 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
216 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
217 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
218 /// <since_tizen> 3 </since_tizen>
219 public static async Task<EyeCondition> RecognizeEyeConditionAsync(MediaVisionSource source,
222 return await RecognizeEyeConditionAsync(source, bound, null);
226 /// Determines eye-blink condition on the media source.
228 /// <param name="source">The source of the media to recognize eye-blink condition for.</param>
229 /// <param name="bound">The bounding the face at the source.</param>
230 /// <param name="config">The configuration used for eye-blink condition recognition. This value can be null.</param>
231 /// <returns>A task that represents the asynchronous recognition operation.</returns>
232 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
233 /// <exception cref="ObjectDisposedException">
234 /// <paramref name="source"/> has already been disposed of.<br/>
236 /// <paramref name="config"/> has already been disposed of.
238 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
239 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
240 /// <since_tizen> 3 </since_tizen>
241 public static async Task<EyeCondition> RecognizeEyeConditionAsync(MediaVisionSource source,
242 Rectangle bound, FaceRecognitionConfiguration config)
246 throw new ArgumentNullException(nameof(source));
249 TaskCompletionSource<EyeCondition> tcs = new TaskCompletionSource<EyeCondition>();
251 InteropFace.EyeConditionRecognizedCallback cb = (IntPtr sourceHandle, IntPtr engineCfgHandle,
252 global::Interop.MediaVision.Rectangle faceLocation, EyeCondition eyeCondition, IntPtr _) =>
254 Log.Info(MediaVisionLog.Tag, $"Eye condition recognized, eye condition : {eyeCondition}");
255 if (!tcs.TrySetResult(eyeCondition))
257 Log.Error(MediaVisionLog.Tag, "Failed to set eye condition result");
261 using (var cbKeeper = ObjectKeeper.Get(cb))
263 InteropFace.RecognizeEyeCondition(source.Handle, EngineConfiguration.GetHandle(config),
264 bound.ToMarshalable(), cb).Validate("Failed to perform eye condition recognition.");
266 return await tcs.Task;
271 /// Determines facial expression on media source.
273 /// <param name="source">The source of the media to recognize facial expression for.</param>
274 /// <param name="bound">The location bounding the face at the source.</param>
275 /// <returns>A task that represents the asynchronous recognition operation.</returns>
276 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
277 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
278 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
279 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
280 /// <since_tizen> 3 </since_tizen>
281 public static async Task<FacialExpression> RecognizeFacialExpressionAsync(MediaVisionSource source,
284 return await RecognizeFacialExpressionAsync(source, bound, null);
288 /// Determines facial expression on media source.
290 /// <param name="source">The source of the media to recognize facial expression for.</param>
291 /// <param name="bound">The location bounding the face at the source.</param>
292 /// <param name="config">The configuration used for expression recognition. This value can be null.</param>
293 /// <returns>A task that represents the asynchronous recognition operation.</returns>
294 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
295 /// <exception cref="ObjectDisposedException">
296 /// <paramref name="source"/> has already been disposed of.<br/>
298 /// <paramref name="config"/> has already been disposed of.
300 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
301 /// <feature>http://tizen.org/feature/vision.face_recognition</feature>
302 /// <since_tizen> 3 </since_tizen>
303 public static async Task<FacialExpression> RecognizeFacialExpressionAsync(MediaVisionSource source,
304 Rectangle bound, FaceRecognitionConfiguration config)
308 throw new ArgumentNullException(nameof(source));
311 TaskCompletionSource<FacialExpression> tcsResult = new TaskCompletionSource<FacialExpression>();
313 InteropFace.MvFaceFacialExpressionRecognizedCallback cb = (IntPtr sourceHandle, IntPtr engineCfgHandle,
314 global::Interop.MediaVision.Rectangle faceLocation, FacialExpression facialExpression, IntPtr _) =>
316 Log.Info(MediaVisionLog.Tag, $"Facial expression recognized, expression : {facialExpression}");
317 if (!tcsResult.TrySetResult(facialExpression))
319 Log.Error(MediaVisionLog.Tag, "Failed to set facial result");
323 using (var cbKeeper = ObjectKeeper.Get(cb))
325 InteropFace.RecognizeFacialExpression(source.Handle, EngineConfiguration.GetHandle(config),
326 bound.ToMarshalable(), cb).
327 Validate("Failed to perform facial expression recognition.");
329 return await tcsResult.Task;