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
25 /// Provides the ability to recognize faces, face expressions and eye condition on image sources.
27 public static class FaceRecognizer
31 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/>.
33 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
34 /// <param name="recognitionModel">The <see cref="FaceRecognitionConfiguration"/> to be used for recognition.</param>
35 /// <returns>A task that represents the asynchronous recognition operation.</returns>
36 /// <exception cref="ArgumentNullException">
37 /// <paramref name="source"/> is null.\n
39 /// <paramref name="recognitionModel"/> is null.
41 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
42 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
43 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
44 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
45 FaceRecognitionModel recognitionModel)
47 return await InvokeRecognizeAsync(source, recognitionModel, null, null);
51 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/> and a bounding box.
53 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
54 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
55 /// <param name="bound">Rectangular box bounding face image on the source.</param>
56 /// <returns>A task that represents the asynchronous recognition operation.</returns>
57 /// <exception cref="ArgumentNullException">
58 /// <paramref name="source"/> is null.\n
60 /// <paramref name="recognitionModel"/> is null.
62 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
63 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
64 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
65 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
66 FaceRecognitionModel recognitionModel, Rectangle bound)
68 return await InvokeRecognizeAsync(source, recognitionModel, bound, null);
72 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/> and <see cref="FaceRecognitionConfiguration"/>.
74 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
75 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
76 /// <param name="config">The configuration used for recognition. This value can be null.</param>
77 /// <returns>A task that represents the asynchronous recognition operation.</returns>
78 /// <exception cref="ArgumentNullException">
79 /// <paramref name="source"/> is null.\n
81 /// <paramref name="recognitionModel"/> is null.
83 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
84 /// <exception cref="ObjectDisposedException">
85 /// <paramref name="source"/> has already been disposed of.\n
87 /// <paramref name="config"/> has already been disposed of.
89 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
90 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
91 FaceRecognitionModel recognitionModel, FaceRecognitionConfiguration config)
93 return await InvokeRecognizeAsync(source, recognitionModel, null, config);
98 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/>, <see cref="FaceRecognitionConfiguration"/>
99 /// and a bounding box.
101 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
102 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
103 /// <param name="bound">Rectangular box bounding face image on the source.</param>
104 /// <param name="config">The <see cref="FaceRecognitionConfiguration"/> used for recognition. This value can be null.</param>
105 /// <returns>A task that represents the asynchronous recognition operation.</returns>
106 /// <exception cref="ArgumentNullException">
107 /// <paramref name="source"/> is null.\n
109 /// <paramref name="recognitionModel"/> is null.
111 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
112 /// <exception cref="ObjectDisposedException">
113 /// <paramref name="source"/> has already been disposed of.\n
115 /// <paramref name="config"/> has already been disposed of.
117 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
118 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
119 FaceRecognitionModel recognitionModel, Rectangle bound, FaceRecognitionConfiguration config)
121 return await InvokeRecognizeAsync(source, recognitionModel, bound, config);
124 private static MediaVisionError InvokeRecognize(IntPtr sourceHandle, IntPtr modelHandle,
125 IntPtr configHandle, InteropFace.RecognizedCallback cb, Rectangle? area)
129 return InteropFace.Recognize(sourceHandle, modelHandle, configHandle, IntPtr.Zero, cb);
132 var rect = area.Value.ToMarshalable();
133 return InteropFace.Recognize(sourceHandle, modelHandle, configHandle, ref rect, cb);
136 private static async Task<FaceRecognitionResult> InvokeRecognizeAsync(MediaVisionSource source,
137 FaceRecognitionModel recognitionModel, Rectangle? area,
138 FaceRecognitionConfiguration config)
142 throw new ArgumentNullException(nameof(source));
144 if (recognitionModel == null)
146 throw new ArgumentNullException(nameof(recognitionModel));
149 TaskCompletionSource<FaceRecognitionResult> tcs = new TaskCompletionSource<FaceRecognitionResult>();
151 using (var cb = ObjectKeeper.Get(GetRecognizedCallback(tcs)))
153 InvokeRecognize(source.Handle, recognitionModel.Handle, EngineConfiguration.GetHandle(config),
154 cb.Target, area).Validate("Failed to perform face recognition.");
156 return await tcs.Task;
160 private static FaceRecognitionResult CreateRecognitionResult(
161 IntPtr faceLocationPtr, IntPtr faceLabelPtr, double confidence)
164 if (faceLabelPtr != IntPtr.Zero)
166 faceLabel = Marshal.ReadInt32(faceLabelPtr);
169 Rectangle? faceLocation = null;
170 if (faceLocationPtr != IntPtr.Zero)
172 var area = Marshal.PtrToStructure<Interop.MediaVision.Rectangle>(faceLocationPtr);
173 faceLocation = area.ToApiStruct();
176 return new FaceRecognitionResult(faceLabelPtr != IntPtr.Zero, confidence, faceLabel, faceLocation);
179 private static InteropFace.RecognizedCallback GetRecognizedCallback(
180 TaskCompletionSource<FaceRecognitionResult> tcs)
182 return (IntPtr sourceHandle, IntPtr recognitionModelHandle,
183 IntPtr engineCfgHandle, IntPtr faceLocationPtr, IntPtr faceLabelPtr, double confidence, IntPtr _) =>
187 if (!tcs.TrySetResult(CreateRecognitionResult(faceLocationPtr, faceLabelPtr, confidence)))
189 Log.Error(MediaVisionLog.Tag, "Failed to set result");
194 MultimediaLog.Error(MediaVisionLog.Tag, "Setting recognition result failed.", e);
195 tcs.TrySetException(e);
201 /// Determines eye-blink condition on media source.
203 /// <param name="source">The source of the media to recognize eye-blink condition for.</param>
204 /// <param name="bound">The bounding the face at the source.</param>
205 /// <param name="config">The configuration used for eye-blink condition recognition. This value can be null.</param>
206 /// <returns>A task that represents the asynchronous recognition operation.</returns>
207 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
208 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
209 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
210 public static async Task<EyeCondition> RecognizeEyeConditionAsync(MediaVisionSource source,
213 return await RecognizeEyeConditionAsync(source, bound, null);
217 /// Determines eye-blink condition on media source.
219 /// <param name="source">The source of the media to recognize eye-blink condition for.</param>
220 /// <param name="bound">The bounding the face at the source.</param>
221 /// <param name="config">The configuration used for eye-blink condition recognition. This value can be null.</param>
222 /// <returns>A task that represents the asynchronous recognition operation.</returns>
223 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
224 /// <exception cref="ObjectDisposedException">
225 /// <paramref name="source"/> has already been disposed of.\n
227 /// <paramref name="config"/> has already been disposed of.
229 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
230 public static async Task<EyeCondition> RecognizeEyeConditionAsync(MediaVisionSource source,
231 Rectangle bound, FaceRecognitionConfiguration config)
235 throw new ArgumentNullException(nameof(source));
238 TaskCompletionSource<EyeCondition> tcs = new TaskCompletionSource<EyeCondition>();
240 InteropFace.EyeConditionRecognizedCallback cb = (IntPtr sourceHandle, IntPtr engineCfgHandle,
241 Interop.MediaVision.Rectangle faceLocation, EyeCondition eyeCondition, IntPtr _) =>
243 Log.Info(MediaVisionLog.Tag, $"Eye condition recognized, eye condition : {eyeCondition}");
244 if (!tcs.TrySetResult(eyeCondition))
246 Log.Error(MediaVisionLog.Tag, "Failed to set eye condition result");
250 using (var cbKeeper = ObjectKeeper.Get(cb))
252 InteropFace.RecognizeEyeCondition(source.Handle, EngineConfiguration.GetHandle(config),
253 bound.ToMarshalable(), cb).Validate("Failed to perform eye condition recognition.");
255 return await tcs.Task;
260 /// Determines facial expression on media source.
262 /// <param name="source">The source of the media to recognize facial expression for.</param>
263 /// <param name="bound">The location bounding the face at the source.</param>
264 /// <param name="config">The configuration used for expression recognition.</param>
265 /// <returns>A task that represents the asynchronous recognition operation.</returns>
266 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
267 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
268 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
269 public static async Task<FacialExpression> RecognizeFacialExpressionAsync(MediaVisionSource source,
272 return await RecognizeFacialExpressionAsync(source, bound, null);
276 /// Determines facial expression on media source.
278 /// <param name="source">The source of the media to recognize facial expression for.</param>
279 /// <param name="bound">The location bounding the face at the source.</param>
280 /// <param name="config">The configuration used for expression recognition. This value can be null.</param>
281 /// <returns>A task that represents the asynchronous recognition operation.</returns>
282 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
283 /// <exception cref="ObjectDisposedException">
284 /// <paramref name="source"/> has already been disposed of.\n
286 /// <paramref name="config"/> has already been disposed of.
288 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
289 public static async Task<FacialExpression> RecognizeFacialExpressionAsync(MediaVisionSource source,
290 Rectangle bound, FaceRecognitionConfiguration config)
294 throw new ArgumentNullException(nameof(source));
297 TaskCompletionSource<FacialExpression> tcsResult = new TaskCompletionSource<FacialExpression>();
299 InteropFace.MvFaceFacialExpressionRecognizedCallback cb = (IntPtr sourceHandle, IntPtr engineCfgHandle,
300 Interop.MediaVision.Rectangle faceLocation, FacialExpression facialExpression, IntPtr _) =>
302 Log.Info(MediaVisionLog.Tag, $"Facial expression recognized, expression : {facialExpression}");
303 if (!tcsResult.TrySetResult(facialExpression))
305 Log.Error(MediaVisionLog.Tag, "Failed to set facial result");
309 using (var cbKeeper = ObjectKeeper.Get(cb))
311 InteropFace.RecognizeFacialExpression(source.Handle, EngineConfiguration.GetHandle(config),
312 bound.ToMarshalable(), cb).
313 Validate("Failed to perform facial expression recognition.");
315 return await tcsResult.Task;