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 /// <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.\n
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 /// <since_tizen> 3</since_tizen>
46 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
47 FaceRecognitionModel recognitionModel)
49 return await InvokeRecognizeAsync(source, recognitionModel, null, null);
53 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/> and a bounding box.
55 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
56 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
57 /// <param name="bound">Rectangular box bounding face image on the source.</param>
58 /// <returns>A task that represents the asynchronous recognition operation.</returns>
59 /// <exception cref="ArgumentNullException">
60 /// <paramref name="source"/> is null.\n
62 /// <paramref name="recognitionModel"/> is null.
64 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
65 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
66 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
67 /// <since_tizen> 3</since_tizen>
68 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
69 FaceRecognitionModel recognitionModel, Rectangle bound)
71 return await InvokeRecognizeAsync(source, recognitionModel, bound, null);
75 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/> and <see cref="FaceRecognitionConfiguration"/>.
77 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
78 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
79 /// <param name="config">The configuration used for recognition. This value can be null.</param>
80 /// <returns>A task that represents the asynchronous recognition operation.</returns>
81 /// <exception cref="ArgumentNullException">
82 /// <paramref name="source"/> is null.\n
84 /// <paramref name="recognitionModel"/> is null.
86 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
87 /// <exception cref="ObjectDisposedException">
88 /// <paramref name="source"/> has already been disposed of.\n
90 /// <paramref name="config"/> has already been disposed of.
92 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
93 /// <since_tizen> 3</since_tizen>
94 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
95 FaceRecognitionModel recognitionModel, FaceRecognitionConfiguration config)
97 return await InvokeRecognizeAsync(source, recognitionModel, null, config);
102 /// Performs face recognition on the source with <see cref="FaceRecognitionModel"/>, <see cref="FaceRecognitionConfiguration"/>
103 /// and a bounding box.
105 /// <param name="source">The <see cref="MediaVisionSource"/> of the media to recognize faces for.</param>
106 /// <param name="recognitionModel">The <see cref="FaceRecognitionModel"/> to be used for recognition.</param>
107 /// <param name="bound">Rectangular box bounding face image on the source.</param>
108 /// <param name="config">The <see cref="FaceRecognitionConfiguration"/> used for recognition. This value can be null.</param>
109 /// <returns>A task that represents the asynchronous recognition operation.</returns>
110 /// <exception cref="ArgumentNullException">
111 /// <paramref name="source"/> is null.\n
113 /// <paramref name="recognitionModel"/> is null.
115 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
116 /// <exception cref="ObjectDisposedException">
117 /// <paramref name="source"/> has already been disposed of.\n
119 /// <paramref name="config"/> has already been disposed of.
121 /// <exception cref="InvalidOperationException"><paramref name="recognitionModel"/> is untrained model.</exception>
122 /// <since_tizen> 3</since_tizen>
123 public static async Task<FaceRecognitionResult> RecognizeAsync(MediaVisionSource source,
124 FaceRecognitionModel recognitionModel, Rectangle bound, FaceRecognitionConfiguration config)
126 return await InvokeRecognizeAsync(source, recognitionModel, bound, config);
129 private static MediaVisionError InvokeRecognize(IntPtr sourceHandle, IntPtr modelHandle,
130 IntPtr configHandle, InteropFace.RecognizedCallback cb, Rectangle? area)
134 return InteropFace.Recognize(sourceHandle, modelHandle, configHandle, IntPtr.Zero, cb);
137 var rect = area.Value.ToMarshalable();
138 return InteropFace.Recognize(sourceHandle, modelHandle, configHandle, ref rect, cb);
141 private static async Task<FaceRecognitionResult> InvokeRecognizeAsync(MediaVisionSource source,
142 FaceRecognitionModel recognitionModel, Rectangle? area,
143 FaceRecognitionConfiguration config)
147 throw new ArgumentNullException(nameof(source));
149 if (recognitionModel == null)
151 throw new ArgumentNullException(nameof(recognitionModel));
154 TaskCompletionSource<FaceRecognitionResult> tcs = new TaskCompletionSource<FaceRecognitionResult>();
156 using (var cb = ObjectKeeper.Get(GetRecognizedCallback(tcs)))
158 InvokeRecognize(source.Handle, recognitionModel.Handle, EngineConfiguration.GetHandle(config),
159 cb.Target, area).Validate("Failed to perform face recognition.");
161 return await tcs.Task;
165 private static FaceRecognitionResult CreateRecognitionResult(
166 IntPtr faceLocationPtr, IntPtr faceLabelPtr, double confidence)
169 if (faceLabelPtr != IntPtr.Zero)
171 faceLabel = Marshal.ReadInt32(faceLabelPtr);
174 Rectangle? faceLocation = null;
175 if (faceLocationPtr != IntPtr.Zero)
177 var area = Marshal.PtrToStructure<global::Interop.MediaVision.Rectangle>(faceLocationPtr);
178 faceLocation = area.ToApiStruct();
181 return new FaceRecognitionResult(faceLabelPtr != IntPtr.Zero, confidence, faceLabel, faceLocation);
184 private static InteropFace.RecognizedCallback GetRecognizedCallback(
185 TaskCompletionSource<FaceRecognitionResult> tcs)
187 return (IntPtr sourceHandle, IntPtr recognitionModelHandle,
188 IntPtr engineCfgHandle, IntPtr faceLocationPtr, IntPtr faceLabelPtr, double confidence, IntPtr _) =>
192 if (!tcs.TrySetResult(CreateRecognitionResult(faceLocationPtr, faceLabelPtr, confidence)))
194 Log.Error(MediaVisionLog.Tag, "Failed to set result");
199 MultimediaLog.Error(MediaVisionLog.Tag, "Setting recognition result failed.", e);
200 tcs.TrySetException(e);
206 /// Determines eye-blink condition on media source.
208 /// <param name="source">The source of the media to recognize eye-blink condition for.</param>
209 /// <param name="bound">The bounding the face at the source.</param>
210 /// <returns>A task that represents the asynchronous recognition operation.</returns>
211 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
212 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
213 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
214 /// <since_tizen> 3</since_tizen>
215 public static async Task<EyeCondition> RecognizeEyeConditionAsync(MediaVisionSource source,
218 return await RecognizeEyeConditionAsync(source, bound, null);
222 /// Determines eye-blink condition on media source.
224 /// <param name="source">The source of the media to recognize eye-blink condition for.</param>
225 /// <param name="bound">The bounding the face at the source.</param>
226 /// <param name="config">The configuration used for eye-blink condition recognition. This value can be null.</param>
227 /// <returns>A task that represents the asynchronous recognition operation.</returns>
228 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
229 /// <exception cref="ObjectDisposedException">
230 /// <paramref name="source"/> has already been disposed of.\n
232 /// <paramref name="config"/> has already been disposed of.
234 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
235 /// <since_tizen> 3</since_tizen>
236 public static async Task<EyeCondition> RecognizeEyeConditionAsync(MediaVisionSource source,
237 Rectangle bound, FaceRecognitionConfiguration config)
241 throw new ArgumentNullException(nameof(source));
244 TaskCompletionSource<EyeCondition> tcs = new TaskCompletionSource<EyeCondition>();
246 InteropFace.EyeConditionRecognizedCallback cb = (IntPtr sourceHandle, IntPtr engineCfgHandle,
247 global::Interop.MediaVision.Rectangle faceLocation, EyeCondition eyeCondition, IntPtr _) =>
249 Log.Info(MediaVisionLog.Tag, $"Eye condition recognized, eye condition : {eyeCondition}");
250 if (!tcs.TrySetResult(eyeCondition))
252 Log.Error(MediaVisionLog.Tag, "Failed to set eye condition result");
256 using (var cbKeeper = ObjectKeeper.Get(cb))
258 InteropFace.RecognizeEyeCondition(source.Handle, EngineConfiguration.GetHandle(config),
259 bound.ToMarshalable(), cb).Validate("Failed to perform eye condition recognition.");
261 return await tcs.Task;
266 /// Determines facial expression on media source.
268 /// <param name="source">The source of the media to recognize facial expression for.</param>
269 /// <param name="bound">The location bounding the face at the source.</param>
270 /// <returns>A task that represents the asynchronous recognition operation.</returns>
271 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
272 /// <exception cref="ObjectDisposedException"><paramref name="source"/> has already been disposed of.</exception>
273 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
274 /// <since_tizen> 3</since_tizen>
275 public static async Task<FacialExpression> RecognizeFacialExpressionAsync(MediaVisionSource source,
278 return await RecognizeFacialExpressionAsync(source, bound, null);
282 /// Determines facial expression on media source.
284 /// <param name="source">The source of the media to recognize facial expression for.</param>
285 /// <param name="bound">The location bounding the face at the source.</param>
286 /// <param name="config">The configuration used for expression recognition. This value can be null.</param>
287 /// <returns>A task that represents the asynchronous recognition operation.</returns>
288 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
289 /// <exception cref="ObjectDisposedException">
290 /// <paramref name="source"/> has already been disposed of.\n
292 /// <paramref name="config"/> has already been disposed of.
294 /// <exception cref="NotSupportedException">The feature is not supported.</exception>
295 /// <since_tizen> 3</since_tizen>
296 public static async Task<FacialExpression> RecognizeFacialExpressionAsync(MediaVisionSource source,
297 Rectangle bound, FaceRecognitionConfiguration config)
301 throw new ArgumentNullException(nameof(source));
304 TaskCompletionSource<FacialExpression> tcsResult = new TaskCompletionSource<FacialExpression>();
306 InteropFace.MvFaceFacialExpressionRecognizedCallback cb = (IntPtr sourceHandle, IntPtr engineCfgHandle,
307 global::Interop.MediaVision.Rectangle faceLocation, FacialExpression facialExpression, IntPtr _) =>
309 Log.Info(MediaVisionLog.Tag, $"Facial expression recognized, expression : {facialExpression}");
310 if (!tcsResult.TrySetResult(facialExpression))
312 Log.Error(MediaVisionLog.Tag, "Failed to set facial result");
316 using (var cbKeeper = ObjectKeeper.Get(cb))
318 InteropFace.RecognizeFacialExpression(source.Handle, EngineConfiguration.GetHandle(config),
319 bound.ToMarshalable(), cb).
320 Validate("Failed to perform facial expression recognition.");
322 return await tcsResult.Task;