Skip to content

Commit

Permalink
feat: marshal DetectionResult (#1089)
Browse files Browse the repository at this point in the history
* feat: marshal DetectionResult

* refactor: init list if null
  • Loading branch information
homuler committed Jan 2, 2024
1 parent 6e5fa2e commit ff0bd1c
Show file tree
Hide file tree
Showing 17 changed files with 320 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2023 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

using System;
using System.Runtime.InteropServices;

namespace Mediapipe
{
[StructLayout(LayoutKind.Sequential)]
internal readonly struct NativeCategory
{
public readonly int index;
public readonly float score;
private readonly IntPtr _categoryName;
private readonly IntPtr _displayName;

public string categoryName => Marshal.PtrToStringAnsi(_categoryName);
public string displayName => Marshal.PtrToStringAnsi(_displayName);
}

[StructLayout(LayoutKind.Sequential)]
internal readonly struct NativeCategories
{
private readonly IntPtr _categories;
public readonly uint categoriesCount;

public ReadOnlySpan<NativeCategory> AsReadOnlySpan()
{
unsafe
{
return new ReadOnlySpan<NativeCategory>((NativeCategory*)_categories, (int)categoriesCount);
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) 2023 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

using System;
using System.Runtime.InteropServices;

namespace Mediapipe
{
[StructLayout(LayoutKind.Sequential)]
internal readonly struct NativeDetection
{
private readonly IntPtr _categories;

public readonly uint categoriesCount;

public readonly NativeRect boundingBox;

private readonly IntPtr _keypoints;

public readonly uint keypointsCount;

public ReadOnlySpan<NativeCategory> categories
{
get
{
unsafe
{
return new ReadOnlySpan<NativeCategory>((NativeCategory*)_categories, (int)categoriesCount);
}
}
}

public ReadOnlySpan<NativeNormalizedKeypoint> keypoints
{
get
{
unsafe
{
return new ReadOnlySpan<NativeNormalizedKeypoint>((NativeNormalizedKeypoint*)_keypoints, (int)keypointsCount);
}
}
}
}

[StructLayout(LayoutKind.Sequential)]
internal readonly struct NativeDetectionResult
{
private readonly IntPtr _detections;
public readonly uint detectionsCount;

public ReadOnlySpan<NativeDetection> AsReadOnlySpan()
{
unsafe
{
return new ReadOnlySpan<NativeDetection>((NativeDetection*)_detections, (int)detectionsCount);
}
}

public void Dispose()
{
UnsafeNativeMethods.mp_tasks_c_components_containers_CppCloseDetectionResult(this);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) 2023 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

using System;
using System.Runtime.InteropServices;

namespace Mediapipe
{
[StructLayout(LayoutKind.Sequential)]
internal readonly struct NativeNormalizedKeypoint
{
public readonly float x;
public readonly float y;
private readonly IntPtr _label;
public readonly float score;
public readonly bool hasScore;

public string label => Marshal.PtrToStringAnsi(_label);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2023 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

using System.Runtime.InteropServices;

namespace Mediapipe
{
[StructLayout(LayoutKind.Sequential)]
internal readonly struct NativeRect
{
public readonly int left;
public readonly int top;
public readonly int bottom;
public readonly int right;
}

[StructLayout(LayoutKind.Sequential)]
internal readonly struct NativeRectF
{
public readonly float left;
public readonly float top;
public readonly float bottom;
public readonly float right;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ namespace Mediapipe
{
internal static partial class UnsafeNativeMethods
{
[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp_Packet__GetDetectionResult(IntPtr packet, out NativeDetectionResult value);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern void mp_tasks_c_components_containers_CppCloseDetectionResult(NativeDetectionResult data);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
public static extern MpReturnCode mp_Packet__GetNormalizedLandmarksVector(IntPtr packet, out NativeNormalizedLandmarksArray value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ internal Category(int index, float score, string categoryName, string displayNam
this.displayName = displayName;
}

internal Category(NativeCategory nativeCategory) : this(
nativeCategory.index,
nativeCategory.score,
nativeCategory.categoryName,
nativeCategory.displayName)
{
}

public static Category CreateFrom(Classification proto)
{
var categoryName = proto.HasLabel ? proto.Label : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

using System;
using System.Collections.Generic;

namespace Mediapipe.Tasks.Components.Containers
Expand Down Expand Up @@ -53,11 +52,11 @@ public static Detection CreateFrom(Mediapipe.Detection proto)

public static void Copy(Mediapipe.Detection proto, ref Detection destination)
{
var categories = destination.categories;
var categories = destination.categories ?? new List<Category>(proto.Score.Count);
categories.Clear();
for (var idx = 0; idx < proto.Score.Count; idx++)
{
destination.categories.Add(new Category(
categories.Add(new Category(
proto.LabelId.Count > idx ? proto.LabelId[idx] : _DefaultCategoryIndex,
proto.Score[idx],
proto.Label.Count > idx ? proto.Label[idx] : "",
Expand Down Expand Up @@ -96,6 +95,27 @@ public static void Copy(Mediapipe.Detection proto, ref Detection destination)
destination = new Detection(categories, boundingBox, keypoints);
}

internal static void Copy(in NativeDetection source, ref Detection destination)
{
var categories = destination.categories ?? new List<Category>((int)source.categoriesCount);
categories.Clear();
foreach (var nativeCategory in source.categories)
{
categories.Add(new Category(nativeCategory));
}

var boundingBox = new Rect(source.boundingBox);

var keypoints = destination.keypoints ?? new List<NormalizedKeypoint>((int)source.keypointsCount);
keypoints.Clear();
foreach (var nativeKeypoint in source.keypoints)
{
keypoints.Add(new NormalizedKeypoint(nativeKeypoint));
}

destination = new Detection(categories, boundingBox, keypoints);
}

public override string ToString()
=> $"{{ \"categories\": {Util.Format(categories)}, \"boundingBox\": {boundingBox}, \"keypoints\": {Util.Format(keypoints)} }}";
}
Expand Down Expand Up @@ -130,22 +150,28 @@ internal static DetectionResult CreateFrom(List<Mediapipe.Detection> detectionsP

internal static void Copy(List<Mediapipe.Detection> source, ref DetectionResult destination)
{
var detections = destination.detections;
if (source.Count < detections.Count)
{
detections.RemoveRange(source.Count, detections.Count - source.Count);
}
var copyCount = Math.Min(source.Count, detections.Count);
for (var i = 0; i < copyCount; i++)
var detections = destination.detections ?? new List<Detection>(source.Count);
detections.ResizeTo(source.Count);

for (var i = 0; i < source.Count; i++)
{
var detection = detections[i];
Detection.Copy(source[i], ref detection);
detections[i] = detection;
}
}

for (var i = copyCount; i < source.Count; i++)
internal static void Copy(NativeDetectionResult source, ref DetectionResult destination)
{
var detections = destination.detections ?? new List<Detection>((int)source.detectionsCount);
detections.ResizeTo((int)source.detectionsCount);

var i = 0;
foreach (var nativeDetection in source.AsReadOnlySpan())
{
detections.Add(Detection.CreateFrom(source[i]));
var detection = detections[i];
Detection.Copy(nativeDetection, ref detection);
detections[i++] = detection;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ internal NormalizedKeypoint(float x, float y, string label, float? score)
this.score = score;
}

internal NormalizedKeypoint(NativeNormalizedKeypoint nativeKeypoint) : this(
nativeKeypoint.x,
nativeKeypoint.y,
nativeKeypoint.label,
#pragma warning disable IDE0004 // for Unity 2020.3.x
nativeKeypoint.hasScore ? (float?)nativeKeypoint.score : null)
#pragma warning restore IDE0004 // for Unity 2020.3.x
{
}

public override string ToString() => $"{{ \"x\": {x}, \"y\": {y}, \"label\": \"{label}\", \"score\": {Util.Format(score)} }}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ namespace Mediapipe.Tasks.Components.Containers
{
public static class PacketExtension
{
public static void GetDetectionResult(this Packet packet, ref DetectionResult value)
{
UnsafeNativeMethods.mp_Packet__GetDetectionResult(packet.mpPtr, out var detectionResult).Assert();
DetectionResult.Copy(detectionResult, ref value);
detectionResult.Dispose();
}

public static void GetNormalizedLandmarksList(this Packet packet, List<NormalizedLandmarks> outs)
{
UnsafeNativeMethods.mp_Packet__GetNormalizedLandmarksVector(packet.mpPtr, out var landmarksArray).Assert();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ internal Rect(int left, int top, int right, int bottom)
this.bottom = bottom;
}

internal Rect(NativeRect nativeRect) : this(nativeRect.left, nativeRect.top, nativeRect.right, nativeRect.bottom) { }

public override string ToString() => $"{{ \"left\": {left}, \"top\": {top}, \"right\": {right}, \"bottom\": {bottom} }}";
}

Expand All @@ -48,6 +50,16 @@ internal Rect(int left, int top, int right, int bottom)
public readonly float right;
public readonly float bottom;

internal RectF(float left, float top, float right, float bottom)
{
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}

internal RectF(NativeRectF nativeRect) : this(nativeRect.left, nativeRect.top, nativeRect.right, nativeRect.bottom) { }

#nullable enable
public override bool Equals(object? obj) => obj is RectF other && Equals(other);
#nullable disable
Expand Down
1 change: 1 addition & 0 deletions mediapipe_api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ cc_library(
"//mediapipe_api/framework/formats:matrix_data",
"//mediapipe_api/framework/formats:rect",
"//mediapipe_api/framework/port:logging",
"//mediapipe_api/tasks/c/components/containers:detection_result",
"//mediapipe_api/tasks/c/components/containers:landmark",
"//mediapipe_api/tasks/cc/vision/face_geometry/proto:face_geometry",
"//mediapipe_api/tasks/cc/core:task_runner",
Expand Down
Loading

0 comments on commit ff0bd1c

Please sign in to comment.