[MediaVision] Add new inference APIs (#6316)
authorHaesu Gwon <haesu.gwon@samsung.com>
Thu, 19 Sep 2024 02:26:21 +0000 (11:26 +0900)
committerGitHub <noreply@github.com>
Thu, 19 Sep 2024 02:26:21 +0000 (11:26 +0900)
* [MediaVision] Add new inference APIs

12 files changed:
src/Tizen.Multimedia.Vision/Interop/Interop.Libraries.cs
src/Tizen.Multimedia.Vision/Interop/Interop.MediaVision.Inference.cs
src/Tizen.Multimedia.Vision/MediaVision/InferenceFaceDetector.cs [new file with mode: 0644]
src/Tizen.Multimedia.Vision/MediaVision/InferenceFaceDetectorResult.cs [new file with mode: 0755]
src/Tizen.Multimedia.Vision/MediaVision/InferenceFacialLandmarkDetector.cs [new file with mode: 0644]
src/Tizen.Multimedia.Vision/MediaVision/InferenceFacialLandmarkDetectorResult.cs [new file with mode: 0755]
src/Tizen.Multimedia.Vision/MediaVision/InferenceImageClassifier.cs [new file with mode: 0644]
src/Tizen.Multimedia.Vision/MediaVision/InferenceImageClassifierResult.cs [new file with mode: 0755]
src/Tizen.Multimedia.Vision/MediaVision/InferenceObjectDetector.cs [new file with mode: 0644]
src/Tizen.Multimedia.Vision/MediaVision/InferenceObjectDetectorResult.cs [new file with mode: 0755]
src/Tizen.Multimedia.Vision/MediaVision/InferencePoseLandmarkDetector.cs [new file with mode: 0644]
src/Tizen.Multimedia.Vision/MediaVision/InferencePoseLandmarkDetectorResult.cs [new file with mode: 0755]

index 3a22309b08faf231b2559591af714584fb00a25b..647eac186124a4d287c228f741382bd951edf58c 100644 (file)
@@ -20,12 +20,17 @@ internal static partial class Interop
     {
         public const string MediaVisionCommon = "libmv_common.so";
         public const string MediaVisionFace = "libmv_face.so";
-        public const string MediaVisionInference = "libmv_inference.so";
         public const string MediaVisionImage = "libmv_image.so";
         public const string MediaVisionSurveillance = "libmv_surveillance.so";
         public const string MediaVisionBarcodeDetector = "libmv_barcode_detector.so";
         public const string MediaVisionBarcodeGenerator = "libmv_barcode_generator.so";
         public const string MediaVisionRoiTracker = "libmv_roi_tracker.so";
         public const string MediaVisionFaceRecognition = "libmv_face_recognition.so"; // It's based on machine learning
+        public const string MediaVisionInference = "libmv_inference.so";
+        public const string MediaVisionInferenceImageClassification = "libmv_image_classification.so"; // Inference image classification
+        public const string MediaVisionInferenceObjectDetection = "libmv_object_detection.so";
+        public const string MediaVisionInferenceFaceDetection = MediaVisionInferenceObjectDetection; // Inference object detection and face detection
+        public const string MediaVisionInferenceFacialLandmarkDetection = "libmv_landmark_detection.so";
+        public const string MediaVisionInferencePoseLandmarkDetection = "libmv_landmark_detection.so"; // Inference facial landmark detection and pose landmark detection
     }
 }
index 2e5d9879231fba8578bcddb305c10480d635c172..dbd93354e86820cb758c077cbc051631b3182353 100644 (file)
@@ -112,5 +112,145 @@ internal static partial class Interop
             internal static extern MediaVisionError DetectPoseLandmark(IntPtr source, IntPtr inference,
                 IntPtr roi, PoseLandmarkDetectedCallback callback, IntPtr userData = default(IntPtr)); // Deprecated in API 12
         }
+
+        internal static partial class InferenceImageClassification
+        {
+            // Newly added inferernce APIs
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_create")]
+            internal static extern MediaVisionError Create(out IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_destroy")]
+            internal static extern MediaVisionError Destroy(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_configure")]
+            internal static extern MediaVisionError Configure(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_prepare")]
+            internal static extern MediaVisionError Prepare(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_inference")]
+            internal static extern MediaVisionError Inference(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_inference_async")]
+            internal static extern MediaVisionError InferenceAsync(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_get_result_count")]
+            internal static extern MediaVisionError GetResultCount(IntPtr handle, out ulong requestOrder, out uint count);
+
+            [DllImport(Libraries.MediaVisionInferenceImageClassification, EntryPoint = "mv_image_classification_get_label")]
+            internal static extern MediaVisionError GetLabels(IntPtr handle, uint index, out IntPtr label);
+        }
+
+        internal static partial class InferenceFaceDetection
+        {
+            // Newly added inferernce APIs
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_create")]
+            internal static extern MediaVisionError Create(out IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_destroy")]
+            internal static extern MediaVisionError Destroy(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_configure")]
+            internal static extern MediaVisionError Configure(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_prepare")]
+            internal static extern MediaVisionError Prepare(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_inference")]
+            internal static extern MediaVisionError Inference(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_inference_async")]
+            internal static extern MediaVisionError InferenceAsync(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_get_result_count")]
+            internal static extern MediaVisionError GetResultCount(IntPtr handle, out ulong requestId, out uint count);
+
+            [DllImport(Libraries.MediaVisionInferenceFaceDetection, EntryPoint = "mv_face_detection_get_bound_box")]
+            internal static extern MediaVisionError GetBoundingBoxes(IntPtr handle, uint index, out int left, out int top, out int right, out int bottom);
+        }
+
+        internal static partial class InferenceObjectDetection
+        {
+            // Newly added inferernce APIs
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_create")]
+            internal static extern MediaVisionError Create(out IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_destroy")]
+            internal static extern MediaVisionError Destroy(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_configure")]
+            internal static extern MediaVisionError Configure(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_prepare")]
+            internal static extern MediaVisionError Prepare(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_inference")]
+            internal static extern MediaVisionError Inference(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_inference_async")]
+            internal static extern MediaVisionError InferenceAsync(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_get_result_count")]
+            internal static extern MediaVisionError GetResultCount(IntPtr handle, out ulong requestId, out uint count);
+
+            [DllImport(Libraries.MediaVisionInferenceObjectDetection, EntryPoint = "mv_object_detection_get_bound_box")]
+            internal static extern MediaVisionError GetBoundingBoxes(IntPtr handle, uint index, out int left, out int top, out int right, out int bottom);
+        }
+
+        internal static partial class InferenceFacialLandmarkDetection
+        {
+            // Newly added inferernce APIs
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_create")]
+            internal static extern MediaVisionError Create(out IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_destroy")]
+            internal static extern MediaVisionError Destroy(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_configure")]
+            internal static extern MediaVisionError Configure(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_prepare")]
+            internal static extern MediaVisionError Prepare(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_inference")]
+            internal static extern MediaVisionError Inference(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_inference_async")]
+            internal static extern MediaVisionError InferenceAsync(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_get_result_count")]
+            internal static extern MediaVisionError GetResultCount(IntPtr handle, out ulong requestId, out uint count);
+
+            [DllImport(Libraries.MediaVisionInferenceFacialLandmarkDetection, EntryPoint = "mv_facial_landmark_get_position")]
+            internal static extern MediaVisionError GetPoints(IntPtr handle, uint index, out uint posX, out uint posY);
+        }
+
+        internal static partial class InferencePoseLandmarkDetection
+        {
+            // Newly added inferernce APIs
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_create")]
+            internal static extern MediaVisionError Create(out IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_destroy")]
+            internal static extern MediaVisionError Destroy(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_configure")]
+            internal static extern MediaVisionError Configure(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_prepare")]
+            internal static extern MediaVisionError Prepare(IntPtr handle);
+
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_inference")]
+            internal static extern MediaVisionError Inference(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_inference_async")]
+            internal static extern MediaVisionError InferenceAsync(IntPtr handle, IntPtr source);
+
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_get_result_count")]
+            internal static extern MediaVisionError GetResultCount(IntPtr handle, out ulong requestId, out uint count);
+
+            [DllImport(Libraries.MediaVisionInferencePoseLandmarkDetection, EntryPoint = "mv_pose_landmark_get_position")]
+            internal static extern MediaVisionError GetPoints(IntPtr handle, uint index, out uint posX, out uint posY);
+        }
     }
 }
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceFaceDetector.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceFaceDetector.cs
new file mode 100644 (file)
index 0000000..a5fede9
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using InteropFD = Interop.MediaVision.InferenceFaceDetection;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Provides the ability to detect faces.
+    /// </summary>
+    /// <feature>http://tizen.org/feature/vision.inference</feature>
+    /// <feature>http://tizen.org/feature/vision.inference.face</feature>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceFaceDetector : IDisposable
+    {
+        private IntPtr _handle;
+        private bool _disposed;
+
+        /// <summary>Initializes a new instance of the <see cref="InferenceFaceDetector"/> class.</summary>
+        /// <exception cref="NotSupportedException">The required features are not supported.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceFaceDetector()
+        {
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.Inference);
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.InferenceFace);
+
+            InteropFD.Create(out _handle).Validate("Failed to create inference face detector.");
+
+            try
+            {
+                InteropFD.Configure(_handle).Validate("Failed to configure inference face detector.");
+                InteropFD.Prepare(_handle).Validate("Failed to prepare inference face detector.");
+            }
+            catch (Exception e)
+            {
+                Log.Error(MediaVisionLog.Tag, e.ToString());
+                InteropFD.Destroy(_handle);
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Finalizes an instance of the InferenceFaceDetector class.
+        /// </summary>
+        ~InferenceFaceDetector()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Detects faces on the source image synchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferenceFaceDetectorResult.BoundingBoxes"/> can be empty, if there's no detected face.
+        /// </remarks>
+        /// <param name="source">The image data to detect faces.</param>
+        /// <returns>The BoundingBoxes of detected face.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceFaceDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceFaceDetectorResult Inference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropFD.Inference(_handle, source.Handle).Validate("Failed to inference face detection.");
+
+            return new InferenceFaceDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Detects faces on the source image asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferenceFaceDetectorResult.BoundingBoxes"/> can be empty, if there's no detected face.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceFaceDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect faces.</param>
+        /// <exception cref="ObjectDisposedException">The InferenceFaceDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public async Task<InferenceFaceDetectorResult> InferenceAsync(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropFD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference face detection.");
+
+            return await Task.Factory.StartNew(() => new InferenceFaceDetectorResult(_handle),
+                CancellationToken.None,
+                TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
+                TaskScheduler.Default);
+        }
+
+        private ulong _requestId = 1;
+        /// <summary>
+        /// Requests detecting faces to get their bounding boxes asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// This function does not guarantee that inference is done when this method returns. The user can get the result by using <see cref="GetRequestResults"/>.<br/>
+        /// If the user calls this method again before the previous one is finished internally, the call will be ignored.<br/>
+        /// <see cref="InferenceFaceDetectorResult.BoundingBoxes"/> can be empty, if there's no detected face.<br/>
+        /// Note that this method could use about twice as much memory as <see cref="InferenceFaceDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect faces.</param>
+        /// <returns>The request ID that indicates the order of requests.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceFaceDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <seealso cref="GetRequestResults"/>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestInference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropFD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference face detection.");
+
+            return _requestId++;
+        }
+
+        /// <summary>
+        /// Gets the bounding boxes as a result of <see cref="RequestInference"/>.
+        /// </summary>
+        /// <remarks>
+        /// If there's no detected face, <see cref="InferenceFaceDetectorResult.BoundingBoxes"/> will be empty.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceFaceDetector.Inference"/>.
+        /// </remarks>
+        /// <returns>The bounding boxes of detected face.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceFaceDetector already has been disposed.</exception>
+        /// <seealso cref="RequestInference"/>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceFaceDetectorResult GetRequestResults()
+        {
+            return new InferenceFaceDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Releases the unmanaged resources used by the InferenceFaceDetector.
+        /// </summary>
+        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+        /// <since_tizen> 12 </since_tizen>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    // to be used if there are any other disposable objects
+                }
+
+                if (_handle != IntPtr.Zero)
+                {
+                    InteropFD.Destroy(_handle);
+                    _handle = IntPtr.Zero;
+                }
+
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Releases all resources used by the InferenceFaceDetector.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        internal void ValidateNotDisposed()
+        {
+            if (_disposed)
+            {
+                Log.Error(MediaVisionLog.Tag, "InferenceFaceDetector handle is disposed.");
+                throw new ObjectDisposedException(nameof(InferenceFaceDetector));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceFaceDetectorResult.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceFaceDetectorResult.cs
new file mode 100755 (executable)
index 0000000..7050d37
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using InteropFD = Interop.MediaVision.InferenceFaceDetection;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Represents the result of <see cref="InferenceFaceDetector"/> operations.
+    /// </summary>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceFaceDetectorResult
+    {
+        internal InferenceFaceDetectorResult(IntPtr handle)
+        {
+            InteropFD.GetResultCount(handle, out ulong requestId, out uint count).
+                Validate("Failed to get result count.");
+
+            RequestId = requestId;
+            var boundingBoxes = new List<Rectangle>();
+
+            for (uint i = 0 ; i < count ; i++)
+            {
+                InteropFD.GetBoundingBoxes(handle, i, out int left, out int top, out int right, out int bottom).
+                    Validate("Failed to get bounding boxes.");
+                boundingBoxes.Add(new Rectangle(left, top, right - left, bottom - top));
+            }
+
+            BoundingBoxes = boundingBoxes;
+        }
+
+        /// <summary>
+        /// Gets the request ID which is matched with request ID of RequestInference() return value.<br/>
+        /// It represents the order of request.
+        /// </summary>
+        /// <value>The request ID that indicates the order of request.</value>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestId { get; }
+
+        /// <summary>
+        /// Gets the bounding boxes of the detected face.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public IEnumerable<Rectangle> BoundingBoxes { get; }
+    }
+}
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceFacialLandmarkDetector.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceFacialLandmarkDetector.cs
new file mode 100644 (file)
index 0000000..a963a62
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using InteropFLD = Interop.MediaVision.InferenceFacialLandmarkDetection;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Provides the ability to detect facial landmarks.
+    /// </summary>
+    /// <feature>http://tizen.org/feature/vision.inference</feature>
+    /// <feature>http://tizen.org/feature/vision.inference.face</feature>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceFacialLandmarkDetector : IDisposable
+    {
+        private IntPtr _handle;
+        private bool _disposed;
+
+        /// <summary>Initializes a new instance of the <see cref="InferenceFacialLandmarkDetector"/> class.</summary>
+        /// <exception cref="NotSupportedException">The required features are not supported.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceFacialLandmarkDetector()
+        {
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.Inference);
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.InferenceFace);
+
+            InteropFLD.Create(out _handle).Validate("Failed to create inference facial landmark detector.");
+
+            try
+            {
+                InteropFLD.Configure(_handle).Validate("Failed to configure inference facial landmark detector.");
+                InteropFLD.Prepare(_handle).Validate("Failed to prepare inference facial landmark detector.");
+            }
+            catch (Exception e)
+            {
+                Log.Error(MediaVisionLog.Tag, e.ToString());
+                InteropFLD.Destroy(_handle);
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Finalizes an instance of the InferenceFacialLandmarkDetector class.
+        /// </summary>
+        ~InferenceFacialLandmarkDetector()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Detects facial landmarks on the source image synchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferenceFacialLandmarkDetectorResult.Points"/> can be empty, if there's no detected facial landmark.
+        /// </remarks>
+        /// <param name="source">The image data to detect facial landmarks.</param>
+        /// <returns>The coordinates of detected facial landmarks.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceFacialLandmarkDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceFacialLandmarkDetectorResult Inference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropFLD.Inference(_handle, source.Handle).Validate("Failed to inference facial landmark detection.");
+
+            return new InferenceFacialLandmarkDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Detects facial landmarks on the source image asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferenceFacialLandmarkDetectorResult.Points"/> can be empty, if there's no detected facial landmark.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceFacialLandmarkDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect facial landmarks.</param>
+        /// <exception cref="ObjectDisposedException">The InferenceFacialLandmarkDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public async Task<InferenceFacialLandmarkDetectorResult> InferenceAsync(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropFLD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference facial landmark detection.");
+
+            return await Task.Factory.StartNew(() => new InferenceFacialLandmarkDetectorResult(_handle),
+                CancellationToken.None,
+                TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
+                TaskScheduler.Default);
+        }
+
+        private ulong _requestId = 1;
+        /// <summary>
+        /// Requests detecting facial landmarks to get their points asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// This function does not guarantee that inference is done when this method returns. The user can get the result by using <see cref="GetRequestResults"/>.<br/>
+        /// If the user calls this method again before the previous one is finished internally, the call will be ignored.<br/>
+        /// <see cref="InferenceFacialLandmarkDetectorResult.Points"/> can be empty, if there's no detected facial landmark.<br/>
+        /// Note that this method could use about twice as much memory as <see cref="InferenceFacialLandmarkDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect facial landmarks.</param>
+        /// <returns>The request ID that indicates the order of requests.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceFacialLandmarkDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <seealso cref="GetRequestResults"/>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestInference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropFLD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference facial landmark detection.");
+            return _requestId++;
+        }
+
+        /// <summary>
+        /// Gets the points as a result of <see cref="RequestInference"/>.
+        /// </summary>
+        /// <remarks>
+        /// If there's no detected facial landmark, <see cref="InferenceFacialLandmarkDetectorResult.Points"/> will be empty.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceFacialLandmarkDetector.Inference"/>.
+        /// </remarks>
+        /// <returns>The points of detected facial landmarks.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceFacialLandmarkDetector already has been disposed.</exception>
+        /// <seealso cref="RequestInference"/>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceFacialLandmarkDetectorResult GetRequestResults()
+        {
+            return new InferenceFacialLandmarkDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Releases the unmanaged resources used by the InferenceFacialLandmarkDetector.
+        /// </summary>
+        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+        /// <since_tizen> 12 </since_tizen>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    // to be used if there are any other disposable objects
+                }
+
+                if (_handle != IntPtr.Zero)
+                {
+                    InteropFLD.Destroy(_handle);
+                    _handle = IntPtr.Zero;
+                }
+
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Releases all resources used by the InferenceFacialLandmarkDetector.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        internal void ValidateNotDisposed()
+        {
+            if (_disposed)
+            {
+                Log.Error(MediaVisionLog.Tag, "InferenceFacialLandmarkDetector handle is disposed.");
+                throw new ObjectDisposedException(nameof(InferenceFacialLandmarkDetector));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceFacialLandmarkDetectorResult.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceFacialLandmarkDetectorResult.cs
new file mode 100755 (executable)
index 0000000..67b7b75
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using InteropFLD = Interop.MediaVision.InferenceFacialLandmarkDetection;
+
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Represents the result of <see cref="InferenceFacialLandmarkDetector"/> operations.
+    /// </summary>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceFacialLandmarkDetectorResult
+    {
+        internal InferenceFacialLandmarkDetectorResult(IntPtr handle)
+        {
+            InteropFLD.GetResultCount(handle, out ulong requestId, out uint count).
+                Validate("Failed to get result count.");
+
+            RequestId = requestId;
+            var points = new List<Point>();
+
+            for (uint i = 0 ; i < count ; i++)
+            {
+                InteropFLD.GetPoints(handle, i, out uint x, out uint y).Validate("Failed to get points.");
+                points.Add(new Point((int)x, (int)y));
+            }
+
+            Points = points;
+        }
+
+        /// <summary>
+        /// Gets the request ID which is matched with request ID of RequestInference() return value.<br/>
+        /// It represents the order of request.
+        /// </summary>
+        /// <value>The request ID that indicates the order of request.</value>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestId { get; }
+
+        /// <summary>
+        /// Gets The coordinates of detected facial landmarks.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public IEnumerable<Point> Points { get; }
+    }
+}
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceImageClassifier.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceImageClassifier.cs
new file mode 100644 (file)
index 0000000..57b7db8
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using InteropIC = Interop.MediaVision.InferenceImageClassification;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Provides the ability to classify image.
+    /// </summary>
+    /// <feature>http://tizen.org/feature/vision.inference</feature>
+    /// <feature>http://tizen.org/feature/vision.inference.image</feature>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceImageClassifier : IDisposable
+    {
+        private IntPtr _handle;
+        private bool _disposed;
+
+        /// <summary>Initializes a new instance of the <see cref="InferenceImageClassifier"/> class.</summary>
+        /// <exception cref="NotSupportedException">The required features are not supported.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceImageClassifier()
+        {
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.Inference);
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.InferenceImage);
+
+            InteropIC.Create(out _handle).Validate("Failed to create inference image classifier.");
+
+            try
+            {
+                InteropIC.Configure(_handle).Validate("Failed to configure inference image classifier.");
+                InteropIC.Prepare(_handle).Validate("Failed to prepare inference image classifier.");
+            }
+            catch (Exception e)
+            {
+                Log.Error(MediaVisionLog.Tag, e.ToString());
+                InteropIC.Destroy(_handle);
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Finalizes an instance of the InferenceImageClassifier class.
+        /// </summary>
+        ~InferenceImageClassifier()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Classifies image synchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferenceImageClassifierResult.Labels"/> can be empty, if image is not classified.
+        /// </remarks>
+        /// <param name="source">The image data to classify.</param>
+        /// <returns>The labels of classified image.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceImageClassifier already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceImageClassifierResult Inference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropIC.Inference(_handle, source.Handle).Validate("Failed to inference image classification");
+
+            return new InferenceImageClassifierResult(_handle);
+        }
+
+        /// <summary>
+        /// Classifies image asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferenceImageClassifierResult.Labels"/> can be empty, if image is not classified.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceImageClassifier.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to classify.</param>
+        /// <exception cref="ObjectDisposedException">The InferenceImageClassifier already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public async Task<InferenceImageClassifierResult> InferenceAsync(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropIC.InferenceAsync(_handle, source.Handle).Validate("Failed to inference image classification");
+
+            return await Task.Factory.StartNew(() => new InferenceImageClassifierResult(_handle),
+                CancellationToken.None,
+                TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
+                TaskScheduler.Default);
+        }
+
+        private ulong _requestId = 1;
+        /// <summary>
+        /// Requests classifing image to get its labels asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// This function does not guarantee that inference is done when this method returns. The user can get the result by using <see cref="GetRequestResults"/>.<br/>
+        /// If the user calls this method again before the previous one is finished internally, the call will be ignored.<br/>
+        /// <see cref="InferenceImageClassifierResult.Labels"/> can be empty, if image is not classified.<br/>
+        /// Note that this method could use about twice as much memory as <see cref="InferenceImageClassifier.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to classify.</param>
+        /// <returns>The request ID that indicates the order of requests.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceImageClassifier already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <seealso cref="GetRequestResults"/>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestInference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropIC.InferenceAsync(_handle, source.Handle).Validate("Failed to inference image classification.");
+
+            return _requestId++;
+        }
+
+        /// <summary>
+        /// Gets the labels as a result of <see cref="RequestInference"/>.
+        /// </summary>
+        /// <remarks>
+        /// If image is not classified, <see cref="InferenceImageClassifierResult.Labels"/> will be empty.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceImageClassifier.Inference"/>.
+        /// </remarks>
+        /// <returns>The labels of classified image.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceImageClassifier already has been disposed.</exception>
+        /// <seealso cref="RequestInference"/>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceImageClassifierResult GetRequestResults()
+        {
+            return new InferenceImageClassifierResult(_handle);
+        }
+
+        /// <summary>
+        /// Releases the unmanaged resources used by the InferenceImageClassifier.
+        /// </summary>
+        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+        /// <since_tizen> 12 </since_tizen>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    // to be used if there are any other disposable objects
+                }
+
+                if (_handle != IntPtr.Zero)
+                {
+                    InteropIC.Destroy(_handle);
+                    _handle = IntPtr.Zero;
+                }
+
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Releases all resources used by the InferenceImageClassifier.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        internal void ValidateNotDisposed()
+        {
+            if (_disposed)
+            {
+                Log.Error(MediaVisionLog.Tag, "InferenceImageClassifier handle is disposed.");
+                throw new ObjectDisposedException(nameof(InferenceImageClassifier));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceImageClassifierResult.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceImageClassifierResult.cs
new file mode 100755 (executable)
index 0000000..70b5918
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using InteropIC = Interop.MediaVision.InferenceImageClassification;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Represents the result of <see cref="InferenceImageClassifier"/> operations.
+    /// </summary>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceImageClassifierResult
+    {
+        internal InferenceImageClassifierResult(IntPtr handle)
+        {
+            InteropIC.GetResultCount(handle, out ulong requestId, out uint count).
+                Validate("Failed to get result count.");
+
+            RequestId = requestId;
+            var labels = new List<string>();
+
+            for (uint i = 0 ; i < count ; i++)
+            {
+                InteropIC.GetLabels(handle, i, out IntPtr label).Validate("Failed to get labels.");
+                labels.Add(Marshal.PtrToStringAnsi(label));
+            }
+
+            Labels = labels;
+        }
+
+        /// <summary>
+        /// Gets the request ID which is matched with request ID of RequestInference() return value.<br/>
+        /// It represents the order of request.
+        /// </summary>
+        /// <value>The request ID that indicates the order of request.</value>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestId { get; }
+
+        /// <summary>
+        /// Gets the labels of the classified image.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public IEnumerable<string> Labels { get; }
+    }
+}
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceObjectDetector.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceObjectDetector.cs
new file mode 100644 (file)
index 0000000..3945e79
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using InteropOD = Interop.MediaVision.InferenceObjectDetection;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Provides the ability to detect object.
+    /// </summary>
+    /// <feature>http://tizen.org/feature/vision.inference</feature>
+    /// <feature>http://tizen.org/feature/vision.inference.image</feature>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceObjectDetector : IDisposable
+    {
+        private IntPtr _handle;
+        private bool _disposed;
+
+        /// <summary>Initializes a new instance of the <see cref="InferenceObjectDetector"/> class.</summary>
+        /// <exception cref="NotSupportedException">The required features are not supported.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceObjectDetector()
+        {
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.Inference);
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.InferenceImage);
+
+            InteropOD.Create(out _handle).Validate("Failed to create inference object detector.");
+
+            try
+            {
+                InteropOD.Configure(_handle).Validate("Failed to configure inference object detector.");
+                InteropOD.Prepare(_handle).Validate("Failed to prepare inference object detector.");
+            }
+            catch (Exception e)
+            {
+                Log.Error(MediaVisionLog.Tag, e.ToString());
+                InteropOD.Destroy(_handle);
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Finalizes an instance of the InferenceObjectDetector class.
+        /// </summary>
+        ~InferenceObjectDetector()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Detects objects on the source image synchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferenceObjectDetectorResult.BoundingBoxes"/> can be empty, if there's no detected object.
+        /// </remarks>
+        /// <param name="source">The image data to detect object.</param>
+        /// <returns>BoundingBoxes of detected object.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceObjectDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceObjectDetectorResult Inference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropOD.Inference(_handle, source.Handle).Validate("Failed to inference object detection.");
+
+            return new InferenceObjectDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Detects objects on the source image asynchronously.
+        /// </summary>
+        /// <remarks>
+        ///<see cref="InferenceObjectDetectorResult.BoundingBoxes"/> can be empty, if there's no detected object.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceObjectDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect object.</param>
+        /// <exception cref="ObjectDisposedException">The InferenceObjectDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public async Task<InferenceObjectDetectorResult> InferenceAsync(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropOD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference object detection.");
+
+            return await Task.Factory.StartNew(() => new InferenceObjectDetectorResult(_handle),
+                CancellationToken.None,
+                TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
+                TaskScheduler.Default);
+        }
+
+        private ulong _requestId = 1;
+        /// <summary>
+        /// Requests detecting objects to get their bounding boxes asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// This function does not guarantee that inference is done when this method returns. The user can get the result by using <see cref="GetRequestResults"/>.<br/>
+        /// If the user calls this method again before the previous one is finished internally, the call will be ignored.<br/>
+        /// <see cref="InferenceObjectDetectorResult.BoundingBoxes"/> can be empty, if there's no detected object.<br/>
+        /// Note that this method could use about twice as much memory as <see cref="InferenceObjectDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect object.</param>
+        /// <returns>The request ID that indicates the order of requests.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceObjectDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <seealso cref="GetRequestResults"/>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestInference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropOD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference object detection.");
+
+            return _requestId++;
+        }
+
+        /// <summary>
+        /// Gets the bounding boxes as a result of <see cref="RequestInference"/>.
+        /// </summary>
+        /// <remarks>
+        /// If there's no detected object, <see cref="InferenceObjectDetectorResult.BoundingBoxes"/> will be empty.<br/>
+        /// This method uses about twice as much memory as <see cref="InferenceObjectDetector.Inference"/>.
+        /// </remarks>
+        /// <returns>The bounding boxes of detected object.</returns>
+        /// <exception cref="ObjectDisposedException">The InferenceObjectDetector already has been disposed.</exception>
+        /// <seealso cref="RequestInference"/>
+        /// <since_tizen> 12 </since_tizen>
+        public InferenceObjectDetectorResult GetRequestResults()
+        {
+            return new InferenceObjectDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Releases the unmanaged resources used by the InferenceObjectDetector.
+        /// </summary>
+        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+        /// <since_tizen> 12 </since_tizen>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    // to be used if there are any other disposable objects
+                }
+
+                if (_handle != IntPtr.Zero)
+                {
+                    InteropOD.Destroy(_handle);
+                    _handle = IntPtr.Zero;
+                }
+
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Releases all resources used by the InferenceObjectDetector.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        internal void ValidateNotDisposed()
+        {
+            if (_disposed)
+            {
+                Log.Error(MediaVisionLog.Tag, "InferenceObjectDetector handle is disposed.");
+                throw new ObjectDisposedException(nameof(InferenceObjectDetector));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferenceObjectDetectorResult.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferenceObjectDetectorResult.cs
new file mode 100755 (executable)
index 0000000..090031a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using InteropOD = Interop.MediaVision.InferenceObjectDetection;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Represents the result of <see cref="InferenceObjectDetector"/> operations.
+    /// </summary>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferenceObjectDetectorResult
+    {
+        internal InferenceObjectDetectorResult(IntPtr handle)
+        {
+            InteropOD.GetResultCount(handle, out ulong requestId, out uint count).
+                Validate("Failed to get result count.");
+
+            RequestId = requestId;
+            var boundingBoxes = new List<Rectangle>();
+
+            for (uint i = 0 ; i < count ; i++)
+            {
+                InteropOD.GetBoundingBoxes(handle, i, out int left, out int top, out int right, out int bottom).
+                    Validate("Failed to get bounding boxes.");
+                boundingBoxes.Add(new Rectangle(left, top, right - left, bottom - top));
+            }
+
+            BoundingBoxes = boundingBoxes;
+        }
+
+        /// <summary>
+        /// Gets the request ID which is matched with request ID of RequestInference() return value.<br/>
+        /// It represents the order of request.
+        /// </summary>
+        /// <value>The request ID that indicates the order of request.</value>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestId { get; }
+
+        /// <summary>
+        /// Gets the bounding boxes of the detected object.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public IEnumerable<Rectangle> BoundingBoxes { get; }
+    }
+}
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferencePoseLandmarkDetector.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferencePoseLandmarkDetector.cs
new file mode 100644 (file)
index 0000000..a16a3f6
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using InteropPLD = Interop.MediaVision.InferencePoseLandmarkDetection;
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Provides the ability to detect pose landmark.
+    /// </summary>
+    /// <feature>http://tizen.org/feature/vision.inference</feature>
+    /// <feature>http://tizen.org/feature/vision.inference.face</feature>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferencePoseLandmarkDetector : IDisposable
+    {
+        private IntPtr _handle;
+        private bool _disposed;
+
+        /// <summary>Initializes a new instance of the <see cref="InferencePoseLandmarkDetector"/> class.</summary>
+        /// <exception cref="NotSupportedException">The required features are not supported.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferencePoseLandmarkDetector()
+        {
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.Inference);
+            ValidationUtil.ValidateFeatureSupported(VisionFeatures.InferenceFace);
+
+            InteropPLD.Create(out _handle).Validate("Failed to create inference pose landmark detector.");
+
+            try
+            {
+                InteropPLD.Configure(_handle).Validate("Failed to configure inference pose landmark detector.");
+                InteropPLD.Prepare(_handle).Validate("Failed to prepare inference pose landmark detector.");
+            }
+            catch (Exception e)
+            {
+                Log.Error(MediaVisionLog.Tag, e.ToString());
+                InteropPLD.Destroy(_handle);
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Finalizes an instance of the InferencePoseLandmarkDetector class.
+        /// </summary>
+        ~InferencePoseLandmarkDetector()
+        {
+            Dispose(false);
+        }
+
+        /// <summary>
+        /// Detects pose landmarks on the source image synchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferencePoseLandmarkDetectorResult.Points"/> can be empty, if there's no detected pose landmark.
+        /// </remarks>
+        /// <param name="source">The image data to detect pose landmark.</param>
+        /// <returns>The coordinates of detected pose landmarks.</returns>
+        /// <exception cref="ObjectDisposedException">The InferencePoseLandmarkDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public InferencePoseLandmarkDetectorResult Inference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropPLD.Inference(_handle, source.Handle).Validate("Failed to inference pose landmark detection.");
+
+            return new InferencePoseLandmarkDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Detects pose landmarks on the source image asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// <see cref="InferencePoseLandmarkDetectorResult.Points"/> can be empty, if there's no detected pose landmark.<br/>
+        /// This method uses about twice as much memory as <see cref="InferencePoseLandmarkDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect pose landmark.</param>
+        /// <exception cref="ObjectDisposedException">The InferencePoseLandmarkDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <since_tizen> 12 </since_tizen>
+        public async Task<InferencePoseLandmarkDetectorResult> InferenceAsync(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropPLD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference pose landmark detection.");
+
+            return await Task.Factory.StartNew(() => new InferencePoseLandmarkDetectorResult(_handle),
+                CancellationToken.None,
+                TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
+                TaskScheduler.Default);
+        }
+
+        private ulong _requestId = 1;
+        /// <summary>
+        /// Requests detecting pose landmarks  to get their points asynchronously.
+        /// </summary>
+        /// <remarks>
+        /// This function does not guarantee that inference is done when this method returns. The user can get the result by using <see cref="GetRequestResults"/>.<br/>
+        /// If the user calls this method again before the previous one is finished internally, the call will be ignored.<br/>
+        /// <see cref="InferencePoseLandmarkDetectorResult.Points"/> can be empty, if there's no detected pose landmark.<br/>
+        /// Note that this method could use about twice as much memory as <see cref="InferencePoseLandmarkDetector.Inference"/>.
+        /// </remarks>
+        /// <param name="source">The image data to detect pose landmark.</param>
+        /// <returns>The request ID that indicates the order of requests.</returns>
+        /// <exception cref="ObjectDisposedException">The InferencePoseLandmarkDetector already has been disposed.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
+        /// <seealso cref="GetRequestResults"/>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestInference(MediaVisionSource source)
+        {
+            ValidateNotDisposed();
+
+            if (source == null)
+            {
+                throw new ArgumentNullException(nameof(source));
+            }
+
+            InteropPLD.InferenceAsync(_handle, source.Handle).Validate("Failed to inference pose landmark detection.");
+
+            return _requestId++;
+        }
+
+        /// <summary>
+        /// Gets the points as a result of <see cref="RequestInference"/>.
+        /// </summary>
+        /// <remarks>
+        /// If there's no detected pose landmark, <see cref="InferencePoseLandmarkDetectorResult.Points"/> will be empty.<br/>
+        /// This method uses about twice as much memory as <see cref="InferencePoseLandmarkDetector.Inference"/>.
+        /// </remarks>
+        /// <returns>The points of detected pose landmark.</returns>
+        /// <exception cref="ObjectDisposedException">The InferencePoseLandmarkDetector already has been disposed.</exception>
+        /// <seealso cref="RequestInference"/>
+        /// <since_tizen> 12 </since_tizen>
+        public InferencePoseLandmarkDetectorResult GetRequestResults()
+        {
+            return new InferencePoseLandmarkDetectorResult(_handle);
+        }
+
+        /// <summary>
+        /// Releases the unmanaged resources used by the InferencePoseLandmarkDetector.
+        /// </summary>
+        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+        /// <since_tizen> 12 </since_tizen>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    // to be used if there are any other disposable objects
+                }
+
+                if (_handle != IntPtr.Zero)
+                {
+                    InteropPLD.Destroy(_handle);
+                    _handle = IntPtr.Zero;
+                }
+
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Releases all resources used by the InferencePoseLandmarkDetector.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        internal void ValidateNotDisposed()
+        {
+            if (_disposed)
+            {
+                Log.Error(MediaVisionLog.Tag, "InferencePoseLandmarkDetector handle is disposed.");
+                throw new ObjectDisposedException(nameof(InferencePoseLandmarkDetector));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.Multimedia.Vision/MediaVision/InferencePoseLandmarkDetectorResult.cs b/src/Tizen.Multimedia.Vision/MediaVision/InferencePoseLandmarkDetectorResult.cs
new file mode 100755 (executable)
index 0000000..d7c9c16
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using InteropPLD = Interop.MediaVision.InferencePoseLandmarkDetection;
+
+
+namespace Tizen.Multimedia.Vision
+{
+    /// <summary>
+    /// Represents the result of <see cref="InferencePoseLandmarkDetector"/> operations.
+    /// </summary>
+    /// <since_tizen> 12 </since_tizen>
+    public class InferencePoseLandmarkDetectorResult
+    {
+        internal InferencePoseLandmarkDetectorResult(IntPtr handle)
+        {
+            InteropPLD.GetResultCount(handle, out ulong requestId, out uint count).
+                Validate("Failed to get result count.");
+
+            RequestId = requestId;
+            var points = new List<Point>();
+
+            for (uint i = 0 ; i < count ; i++)
+            {
+                InteropPLD.GetPoints(handle, i, out uint x, out uint y).Validate("Failed to get points.");
+                points.Add(new Point((int)x, (int)y));
+            }
+
+            Points = points;
+        }
+
+        /// <summary>
+        /// Gets the request ID which is matched with request ID of RequestInference() return value.<br/>
+        /// It represents the order of request.
+        /// </summary>
+        /// <value>The request ID that indicates the order of request.</value>
+        /// <since_tizen> 12 </since_tizen>
+        public ulong RequestId { get; }
+
+        /// <summary>
+        /// Gets the coordinates of detected pose landmarks.
+        /// </summary>
+        /// <since_tizen> 12 </since_tizen>
+        public IEnumerable<Point> Points { get; }
+    }
+}