[Feature] Sync csharp apis with newly added c apis && demo (#1718)

* sync c api to c#

* fix typo

* add pose tracker c# demo

* udpate gitignore

* remove print

* fix lint

* update rotated detection api

* update rotated detection demo

* rename pose_tracking -> pose_tracker

* use input size as default
pull/1828/head
Chen Xin 2023-03-02 09:20:41 +08:00 committed by GitHub
parent 7fed511f09
commit 7de413a19c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1146 additions and 1 deletions

3
.gitignore vendored
View File

@ -164,3 +164,6 @@ service/snpe/grpc_cpp_plugin
csrc/mmdeploy/preprocess/elena/json
csrc/mmdeploy/preprocess/elena/cpu_kernel/*
csrc/mmdeploy/preprocess/elena/cuda_kernel/*
# c#
demo/csharp/*/Properties

View File

@ -0,0 +1,69 @@
namespace MMDeploy
{
/// <summary>
/// Context.
/// </summary>
public class Context : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="Context"/> class.
/// </summary>
public Context()
{
ThrowException(NativeMethods.mmdeploy_context_create(out _handle));
}
/// <summary>
/// Initializes a new instance of the <see cref="Context"/> class with device.
/// </summary>
/// <param name="device">device.</param>
public Context(Device device) : this()
{
Add(device);
}
/// <summary>
/// Add model to the context.
/// </summary>
/// <param name="name">name.</param>
/// <param name="model">model.</param>
public void Add(string name, Model model)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.MODEL, name, model));
}
/// <summary>
/// Add scheduler to the context.
/// </summary>
/// <param name="name">name.</param>
/// <param name="scheduler">scheduler.</param>
public void Add(string name, Scheduler scheduler)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.SCHEDULER, name, scheduler));
}
/// <summary>
/// Add device to the context.
/// </summary>
/// <param name="device">device.</param>
public void Add(Device device)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.DEVICE, "", device));
}
/// <summary>
/// Add profiler to the context.
/// </summary>
/// <param name="profiler">profiler.</param>
public void Add(Profiler profiler)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.PROFILER, "", profiler));
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_model_destroy(_handle);
}
}
}

View File

@ -0,0 +1,39 @@
namespace MMDeploy
{
/// <summary>
/// Device.
/// </summary>
public class Device : DisposableObject
{
private readonly string _name;
private readonly int _index;
/// <summary>
/// Initializes a new instance of the <see cref="Device"/> class.
/// </summary>
/// <param name="name">device name.</param>
/// <param name="index">device index.</param>
public Device(string name, int index = 0)
{
this._name = name;
this._index = index;
ThrowException(NativeMethods.mmdeploy_device_create(name, index, out _handle));
}
/// <summary>
/// Gets device name.
/// </summary>
public string Name { get => _name; }
/// <summary>
/// Gets device index.
/// </summary>
public int Index { get => _index; }
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_device_destroy(_handle);
}
}
}

View File

@ -92,5 +92,11 @@ namespace MMDeploy
throw new Exception(result.ToString());
}
}
/// <summary>
/// Gets internal handle.
/// </summary>
/// <param name="obj">instance.</param>
public static implicit operator IntPtr(DisposableObject obj) => obj._handle;
}
}

View File

@ -0,0 +1,23 @@
namespace MMDeploy
{
/// <summary>
/// model.
/// </summary>
public class Model : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="Model"/> class.
/// </summary>
/// <param name="modelPath">model path.</param>
public Model(string modelPath)
{
ThrowException(NativeMethods.mmdeploy_model_create_by_path(modelPath, out _handle));
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_model_destroy(_handle);
}
}
}

View File

@ -0,0 +1,350 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace MMDeploy
{
#pragma warning disable 0649
internal unsafe struct CPoseTrack
{
public Pointf* Keypoints;
public int KeypointCount;
public float* Scores;
public Rect Bbox;
public int TargetId;
}
#pragma warning restore 0649
/// <summary>
/// Single tracking result of a bbox.
/// A picture may contains multiple reuslts.
/// </summary>
public struct PoseTrack
{
/// <summary>
/// Keypoints.
/// </summary>
public List<Pointf> Keypoints;
/// <summary>
/// Scores.
/// </summary>
public List<float> Scores;
/// <summary>
/// Bbox.
/// </summary>
public Rect Bbox;
/// <summary>
/// TargetId.
/// </summary>
public int TargetId;
/// <summary>
/// Init data.
/// </summary>
private void Init()
{
if (Keypoints == null || Scores == null)
{
Keypoints = new List<Pointf>();
Scores = new List<float>();
}
}
internal unsafe void Add(CPoseTrack* result)
{
Init();
for (int i = 0; i < result->KeypointCount; i++)
{
Keypoints.Add(new Pointf(result->Keypoints[i].X, result->Keypoints[i].Y));
Scores.Add(result->Scores[i]);
}
Bbox = result->Bbox;
TargetId = result->TargetId;
}
}
/// <summary>
/// Output of PoseTracker.
/// </summary>
public struct PoseTrackerOutput
{
/// <summary>
/// Tracking results for single image.
/// </summary>
public List<PoseTrack> Results;
/// <summary>
/// Gets number of output.
/// </summary>
public int Count
{
get { return (Results == null) ? 0 : Results.Count; }
}
/// <summary>
/// Result for box level.
/// </summary>
/// <param name="boxRes">Box res.</param>
public void Add(PoseTrack boxRes)
{
if (Results == null)
{
Results = new List<PoseTrack>();
}
Results.Add(boxRes);
}
}
/// <summary>
/// PoseTracker.
/// </summary>
public class PoseTracker : DisposableObject
{
/// <summary>
/// Params.
/// </summary>
public struct Params
{
/// <summary>
/// init with default value.
/// </summary>
public void Init()
{
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Params)));
NativeMethods.mmdeploy_pose_tracker_default_params(ptr);
this = Marshal.PtrToStructure<Params>(ptr);
Marshal.DestroyStructure<Params>(ptr);
Marshal.FreeHGlobal(ptr);
}
/// <summary>
/// Sets keypoint sigmas.
/// </summary>
/// <param name="array">keypoint sigmas.</param>
public void SetKeypointSigmas(float[] array)
{
this.KeypointSigmasSize = array.Length;
this.KeypointSigmas = Marshal.AllocHGlobal(sizeof(float) * array.Length);
Marshal.Copy(array, 0, this.KeypointSigmas, array.Length);
}
/// <summary>
/// Release ptr.
/// </summary>
public void DeleteKeypointSigmas()
{
if (this.KeypointSigmas != null)
{
Marshal.FreeHGlobal(this.KeypointSigmas);
this.KeypointSigmasSize = 0;
}
}
/// <summary>
/// detection interval, default = 1.
/// </summary>
public int DetInterval;
/// <summary>
/// detection label use for pose estimation, default = 0.
/// </summary>
public int DetLabel;
/// <summary>
/// detection score threshold, default = 0.5.
/// </summary>
public float DetThr;
/// <summary>
/// detection minimum bbox size (compute as sqrt(area)), default = -1.
/// </summary>
public float DetMinBboxSize;
/// <summary>
/// nms iou threshold for merging detected bboxes and bboxes from tracked targets, default = 0.7.
/// </summary>
public float DetNmsThr;
/// <summary>
/// max number of bboxes used for pose estimation per frame, default = -1.
/// </summary>
public int PoseMaxNumBboxes;
/// <summary>
/// threshold for visible key-points, default = 0.5.
/// </summary>
public float PoseKptThr;
/// <summary>
/// min number of key-points for valid poses, default = -1.
/// </summary>
public int PoseMinKeypoints;
/// <summary>
/// scale for expanding key-points to bbox, default = 1.25.
/// </summary>
public float PoseBboxScale;
/// <summary>
/// min pose bbox size, tracks with bbox size smaller than the threshold will be dropped,default = -1.
/// </summary>
public float PoseMinBboxSize;
/// <summary>
/// nms oks/iou threshold for suppressing overlapped poses, useful when multiple pose estimations
/// collapse to the same target, default = 0.5.
/// </summary>
public float PoseNmsThr;
/// <summary>
/// keypoint sigmas for computing OKS, will use IOU if not set, default = nullptr.
/// </summary>
public IntPtr KeypointSigmas;
/// <summary>
/// size of keypoint sigma array, must be consistent with the number of key-points, default = 0.
/// </summary>
public int KeypointSigmasSize;
/// <summary>
/// iou threshold for associating missing tracks, default = 0.4.
/// </summary>
public float TrackIouThr;
/// <summary>
/// max number of missing frames before a missing tracks is removed, default = 10.
/// </summary>
public int TrackMaxMissing;
/// <summary>
/// track history size, default = 1.
/// </summary>
public int TrackHistorySize;
/// <summary>
/// weight of position for setting covariance matrices of kalman filters, default = 0.05.
/// </summary>
public float StdWeightPosition;
/// <summary>
/// weight of velocity for setting covariance matrices of kalman filters, default = 0.00625.
/// </summary>
public float StdWeightVelocity;
/// <summary>
/// params for the one-euro filter for smoothing the outputs - (beta, fc_min, fc_derivative)
/// default = (0.007, 1, 1).
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public float[] SmoothParams;
}
/// <summary>
/// tracking state.
/// </summary>
public class State : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="State"/> class.
/// </summary>
/// <param name="pipeline">pipeline.</param>
/// <param name="param">param.</param>
public State(IntPtr pipeline, Params param)
{
ThrowException(NativeMethods.mmdeploy_pose_tracker_create_state(pipeline, param, out _handle));
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_pose_tracker_destroy_state(_handle);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="PoseTracker"/> class.
/// </summary>
/// <param name="detect">detect model.</param>
/// <param name="pose">pose model.</param>
/// <param name="context">context.</param>
public PoseTracker(Model detect, Model pose, Context context)
{
ThrowException(NativeMethods.mmdeploy_pose_tracker_create(detect, pose, context, out _handle));
}
/// <summary>
/// Get track information of image.
/// </summary>
/// <param name="state">state for video.</param>
/// <param name="mat">input mat.</param>
/// <param name="detect">control the use of detector.
/// -1: use params.DetInterval, 0: don't use detector, 1: force use detector.</param>
/// <returns>results of this frame.</returns>
public PoseTrackerOutput Apply(State state, Mat mat, int detect = -1)
{
PoseTrackerOutput output = default;
IntPtr[] states = new IntPtr[1] { state };
Mat[] mats = new Mat[1] { mat };
int[] detects = new int[1] { -1 };
unsafe
{
CPoseTrack* results = null;
int* resultCount = null;
fixed (Mat* _mats = mats)
fixed (IntPtr* _states = states)
fixed (int* _detects = detects)
{
ThrowException(NativeMethods.mmdeploy_pose_tracker_apply(_handle, _states, _mats, _detects,
mats.Length, &results, &resultCount));
FormatResult(resultCount, results, ref output, out var total);
ReleaseResult(results, resultCount, mats.Length);
}
}
return output;
}
private unsafe void FormatResult(int* resultCount, CPoseTrack* results, ref PoseTrackerOutput output, out int total)
{
total = resultCount[0];
for (int i = 0; i < total; i++)
{
PoseTrack outi = default;
outi.Add(results);
output.Add(outi);
results++;
}
}
private unsafe void ReleaseResult(CPoseTrack* results, int* resultCount, int count)
{
NativeMethods.mmdeploy_pose_tracker_release_result(results, resultCount, count);
}
/// <summary>
/// Create internal state.
/// </summary>
/// <param name="param">instance of Params.</param>
/// <returns>instance of State.</returns>
public State CreateState(Params param)
{
State state = new State(_handle, param);
return state;
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
// _state.Dispose();
NativeMethods.mmdeploy_pose_tracker_destroy(_handle);
}
}
}

View File

@ -0,0 +1,23 @@
namespace MMDeploy
{
/// <summary>
/// Profiler.
/// </summary>
public class Profiler : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="Profiler"/> class.
/// </summary>
/// <param name="path">path.</param>
public Profiler(string path)
{
ThrowException(NativeMethods.mmdeploy_profiler_create(path, out _handle));
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_profiler_destroy(_handle);
}
}
}

View File

@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
namespace MMDeploy
{
/// <summary>
/// Single detection result of a picture.
/// A picture may contains multiple reuslts.
/// </summary>
public struct RDetect
{
/// <summary>
/// Label id.
/// </summary>
public int LabelId;
/// <summary>
/// Score.
/// </summary>
public float Score;
/// <summary>
/// Center x.
/// </summary>
public float Cx;
/// <summary>
/// Center y.
/// </summary>
public float Cy;
/// <summary>
/// Width.
/// </summary>
public float Width;
/// <summary>
/// Height.
/// </summary>
public float Height;
/// <summary>
/// Angle.
/// </summary>
public float Angle;
internal unsafe RDetect(RDetect* result) : this()
{
this = *result;
}
}
/// <summary>
/// Output of RotatedDetector.
/// </summary>
public struct RotatedDetectorOutput
{
/// <summary>
/// Rotated detection results for single image.
/// </summary>
public List<RDetect> Results;
private void Init()
{
if (Results == null)
{
Results = new List<RDetect>();
}
}
internal unsafe void Add(RDetect* result)
{
Init();
Results.Add(new RDetect(result));
}
/// <summary>
/// Gets number of output.
/// </summary>
public int Count
{
get { return (Results == null) ? 0 : Results.Count; }
}
}
/// <summary>
/// RotatedDetector.
/// </summary>
public class RotatedDetector : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="RotatedDetector"/> class.
/// </summary>
/// <param name="modelPath">model path.</param>
/// <param name="deviceName">device name.</param>
/// <param name="deviceId">device id.</param>
public RotatedDetector(string modelPath, string deviceName, int deviceId)
{
ThrowException(NativeMethods.mmdeploy_rotated_detector_create_by_path(modelPath,
deviceName, deviceId, out _handle));
}
/// <summary>
/// Get information of each image in a batch.
/// </summary>
/// <param name="mats">input mats.</param>
/// <returns>Results of each input mat.</returns>
public List<RotatedDetectorOutput> Apply(Mat[] mats)
{
List<RotatedDetectorOutput> output = new List<RotatedDetectorOutput>();
unsafe
{
RDetect* results = null;
int* resultCount = null;
fixed (Mat* _mats = mats)
{
ThrowException(NativeMethods.mmdeploy_rotated_detector_apply(_handle,
_mats, mats.Length, &results, &resultCount));
}
FormatResult(mats.Length, resultCount, results, ref output, out var total);
ReleaseResult(results, resultCount);
}
return output;
}
private unsafe void FormatResult(int matCount, int* resultCount, RDetect* results,
ref List<RotatedDetectorOutput> output, out int total)
{
total = matCount;
for (int i = 0; i < matCount; i++)
{
RotatedDetectorOutput outi = default;
for (int j = 0; j < resultCount[i]; j++)
{
outi.Add(results);
results++;
}
output.Add(outi);
}
}
private unsafe void ReleaseResult(RDetect* results, int* resultCount)
{
NativeMethods.mmdeploy_rotated_detector_release_result(results, resultCount);
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_rotated_detector_destroy(_handle);
}
}
}

View File

@ -0,0 +1,51 @@
using System;
namespace MMDeploy
{
/// <summary>
/// Scheduler.
/// </summary>
public class Scheduler : DisposableObject
{
private Scheduler()
{
}
/// <summary>
/// Create thread pool scheduler.
/// </summary>
/// <param name="num_threads">thread number.</param>
/// <returns>scheduler.</returns>
public static Scheduler ThreadPool(int num_threads)
{
Scheduler result = new Scheduler();
unsafe
{
result._handle = (IntPtr)NativeMethods.mmdeploy_executor_create_thread_pool(num_threads);
}
return result;
}
/// <summary>
/// Create single thread scheduler.
/// </summary>
/// <returns>scheduler.</returns>
public static Scheduler Thread()
{
Scheduler result = new Scheduler();
unsafe
{
result._handle = (IntPtr)NativeMethods.mmdeploy_executor_create_thread();
}
return result;
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_scheduler_destroy(_handle);
}
}
}

View File

@ -99,7 +99,7 @@ namespace MMDeploy
}
/// <summary>
/// Output of DetectorOutput.
/// Output of TextDetector.
/// </summary>
public struct TextDetectorOutput
{

View File

@ -89,4 +89,17 @@ namespace MMDeploy
Y = y;
}
}
/// <summary>
/// Context type.
/// </summary>
public enum ContextType
{
DEVICE = 0,
STREAM = 1,
MODEL = 2,
SCHEDULER = 3,
MAT = 4,
PROFILER = 5,
}
}

View File

@ -9,6 +9,37 @@ namespace MMDeploy
/// </summary>
internal static partial class NativeMethods
{
#region common.h
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_context_create(out IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_context_create_by_device(string deviceName, int deviceId,
out IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void mmdeploy_context_destroy(IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_context_add(IntPtr handle, int type, string name,
IntPtr obj);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_device_create(string device_name, int device_id,
out IntPtr device);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void mmdeploy_device_destroy(IntPtr device);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_profiler_create(string path, out IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern unsafe void mmdeploy_profiler_destroy(IntPtr handle);
#endregion
#region scheduler.h
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern unsafe void* mmdeploy_executor_create_thread();
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern unsafe void* mmdeploy_executor_create_thread_pool(int num_threads);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void mmdeploy_scheduler_destroy(IntPtr handle);
#endregion
#region model.h
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_model_create_by_path(string path, out IntPtr handle);
@ -38,6 +69,27 @@ namespace MMDeploy
public static extern void mmdeploy_pose_detector_destroy(IntPtr handle);
#endregion
#region pose_tracker.h
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_pose_tracker_create(IntPtr det_model, IntPtr pose_model,
IntPtr context, out IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_pose_tracker_destroy(IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_pose_tracker_default_params(IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_pose_tracker_create_state(IntPtr pipeline,
PoseTracker.Params param, out IntPtr state);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void mmdeploy_pose_tracker_destroy_state(IntPtr state);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern unsafe int mmdeploy_pose_tracker_apply(IntPtr handle, IntPtr* state,
Mat* mats, int* useDet, int count, CPoseTrack** results, int** resultCount);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern unsafe void mmdeploy_pose_tracker_release_result(CPoseTrack* results,
int* resultCount, int count);
#endregion
#region classifier.h
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_classifier_create(IntPtr model, string deviceName,
@ -55,6 +107,23 @@ namespace MMDeploy
public static extern void mmdeploy_classifier_destroy(IntPtr handle);
#endregion
#region rotated_detector.h
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_rotated_detector_create(IntPtr model,
string deviceName, int deviceId, out IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_rotated_detector_create_by_path(string modelPath,
string deviceName, int deviceId, out IntPtr handle);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern unsafe int mmdeploy_rotated_detector_apply(IntPtr handle, Mat* mats,
int matCount, RDetect** results, int** resultCount);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern unsafe void mmdeploy_rotated_detector_release_result(RDetect* results,
int* resultCount);
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void mmdeploy_rotated_detector_destroy(IntPtr handle);
#endregion
#region detector.h
[Pure, DllImport(DllExtern, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int mmdeploy_detector_create(IntPtr model, string deviceName,

View File

@ -17,6 +17,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ocr_recognition", "ocr_reco
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "pose_detection", "pose_detection\pose_detection.csproj", "{10E3B87C-7544-4F4D-90A3-65D5654CBF94}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "pose_tracker", "pose_tracker\pose_tracker.csproj", "{42FC54A1-73D5-429D-AF5E-09BAEC4F0D9E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "rotated_detection", "rotated_detection\rotated_detection.csproj", "{1957C2D2-F6D1-4E28-920C-2B7DE98EAF50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -51,6 +55,14 @@ Global
{10E3B87C-7544-4F4D-90A3-65D5654CBF94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{10E3B87C-7544-4F4D-90A3-65D5654CBF94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{10E3B87C-7544-4F4D-90A3-65D5654CBF94}.Release|Any CPU.Build.0 = Release|Any CPU
{42FC54A1-73D5-429D-AF5E-09BAEC4F0D9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42FC54A1-73D5-429D-AF5E-09BAEC4F0D9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42FC54A1-73D5-429D-AF5E-09BAEC4F0D9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42FC54A1-73D5-429D-AF5E-09BAEC4F0D9E}.Release|Any CPU.Build.0 = Release|Any CPU
{1957C2D2-F6D1-4E28-920C-2B7DE98EAF50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1957C2D2-F6D1-4E28-920C-2B7DE98EAF50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1957C2D2-F6D1-4E28-920C-2B7DE98EAF50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1957C2D2-F6D1-4E28-920C-2B7DE98EAF50}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,203 @@
using System;
using System.Collections.Generic;
using OpenCvSharp;
using MMDeploy;
using System.Linq;
namespace pose_tracker
{
internal class Program
{
static class CocoSkeleton
{
public static List<(int, int)> Skeleton = new List<(int, int)>
{
(15, 13), (13, 11), (16, 14), (14, 12), (11, 12), (5, 11), (6, 12),
(5, 6), (5, 7), (6, 8), (7, 9), (8, 10), (1, 2), (0, 1),
(0, 2), (1, 3), (2, 4), (3, 5), (4, 6)
};
public static List<Scalar> Palette = new List<Scalar>
{
new Scalar(255, 128, 0), new Scalar(255, 153, 51), new Scalar(255, 178, 102),
new Scalar(230, 230, 0), new Scalar(255, 153, 255), new Scalar(153, 204, 255),
new Scalar(255, 102, 255), new Scalar(255, 51, 255), new Scalar(102, 178, 255),
new Scalar(51, 153, 255), new Scalar(255, 153, 153), new Scalar(255, 102, 102),
new Scalar(255, 51, 51), new Scalar(153, 255, 153), new Scalar(102, 255, 102),
new Scalar(51, 255, 51), new Scalar(0, 255, 0), new Scalar(0, 0, 255),
new Scalar(255, 0, 0), new Scalar(255, 255, 255),
};
public static List<int> LinkColor = new List<int>
{
0, 0, 0, 0, 7, 7, 7, 9, 9, 9, 9, 9, 16, 16, 16, 16, 16, 16, 16
};
public static List<int> PointColor = new List<int>
{
16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0
};
}
static bool Visualize(OpenCvSharp.Mat frame, PoseTrackerOutput result, int long_edge,
int frame_id, bool with_bbox)
{
var skeleton = CocoSkeleton.Skeleton;
var palette = CocoSkeleton.Palette;
var link_color = CocoSkeleton.LinkColor;
var point_color = CocoSkeleton.PointColor;
float scale = 1;
if (long_edge != 0)
{
scale = (float)long_edge / (float)Math.Max(frame.Cols, frame.Rows);
}
if (scale != 1)
{
Cv2.Resize(frame, frame, new Size(), scale, scale);
}
else
{
frame = frame.Clone();
}
Action<List<float>, Scalar> drawBbox = (bbox, color) =>
{
for (int i = 0; i < bbox.Count; i++)
{
bbox[i] *= scale;
}
Cv2.Rectangle(frame, new OpenCvSharp.Point(bbox[0], bbox[1]),
new OpenCvSharp.Point(bbox[2], bbox[3]), color);
};
for (int i = 0; i < result.Count; i++)
{
PoseTrack pt = result.Results[i];
for (int j = 0; j < pt.Keypoints.Count; j++)
{
Pointf p = pt.Keypoints[j];
p.X *= scale;
p.Y *= scale;
pt.Keypoints[j] = p;
}
float score_thr = 0.5f;
int[] used = new int[pt.Keypoints.Count * 2];
for (int j = 0; j < skeleton.Count; j++)
{
int u = skeleton[j].Item1;
int v = skeleton[j].Item2;
if (pt.Scores[u] > score_thr && pt.Scores[v] > score_thr)
{
used[u] = used[v] = 1;
var p_u = new OpenCvSharp.Point(pt.Keypoints[u].X, pt.Keypoints[u].Y);
var p_v = new OpenCvSharp.Point(pt.Keypoints[v].X, pt.Keypoints[v].Y);
Cv2.Line(frame, p_u, p_v, palette[link_color[j]], 1, LineTypes.AntiAlias);
}
}
for (int j = 0; j < pt.Keypoints.Count; j++)
{
if (used[j] == 1)
{
var p = new OpenCvSharp.Point(pt.Keypoints[j].X, pt.Keypoints[j].Y);
Cv2.Circle(frame, p, 1, palette[point_color[j]], 2, LineTypes.AntiAlias);
}
}
if (with_bbox)
{
var bbox = new List<float> { pt.Bbox.Left, pt.Bbox.Top, pt.Bbox.Right, pt.Bbox.Bottom };
drawBbox(bbox, new Scalar(0, 255, 0));
}
}
Cv2.ImShow("pose_tracker", frame);
return Cv2.WaitKey(1) != 'q';
}
static void CvMatToMat(OpenCvSharp.Mat cvMat, out MMDeploy.Mat mat)
{
mat = new MMDeploy.Mat();
unsafe
{
mat.Data = cvMat.DataPointer;
mat.Height = cvMat.Height;
mat.Width = cvMat.Width;
mat.Channel = cvMat.Dims;
mat.Format = PixelFormat.BGR;
mat.Type = DataType.Int8;
mat.Device = null;
}
}
static void PrintHelperMessage()
{
string message = "usage:\n pose_tracker device det_model pose_model video";
Console.WriteLine(message);
}
static void Main(string[] args)
{
if (args.Length != 4)
{
PrintHelperMessage();
Environment.Exit(1);
}
string device_ = args[0];
string det_model_ = args[1];
string pose_model_ = args[2];
string video = args[3];
Model det_model = new Model(det_model_);
Model pose_model = new Model(pose_model_);
Device device = new Device(device_);
Context context = new Context(device);
// initialize tracker
PoseTracker tracker = new PoseTracker(det_model, pose_model, context);
PoseTracker.Params param = new PoseTracker.Params();
// set default param
param.Init();
// set custom param
param.DetMinBboxSize = 100;
param.DetInterval = 1;
param.PoseMaxNumBboxes = 6;
// optionally use OKS for keypoints similarity comparison
float[] sigmas = {0.026f, 0.025f, 0.025f, 0.035f, 0.035f, 0.079f, 0.079f, 0.072f, 0.072f,
0.062f, 0.062f, 0.107f, 0.107f, 0.087f, 0.087f, 0.089f, 0.089f };
param.SetKeypointSigmas(sigmas);
// create state
PoseTracker.State state = tracker.CreateState(param);
VideoCapture cap = new VideoCapture(video);
if (!cap.IsOpened())
{
Console.WriteLine("failed to open video: " + video);
Environment.Exit(1);
}
int frame_id = 0;
OpenCvSharp.Mat frame = new OpenCvSharp.Mat();
while (true)
{
cap.Read(frame);
if (frame.Empty())
{
break;
}
CvMatToMat(frame, out var mat);
// process
PoseTrackerOutput result = tracker.Apply(state, mat);
// visualize
if (!Visualize(frame, result, 0, frame_id++, true))
{
break;
}
}
param.DeleteKeypointSigmas();
tracker.Close();
}
}
}

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MMDeployCSharp" Version="0.12.0" />
<PackageReference Include="OpenCvSharp4" Version="4.5.5.20211231" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.5.5.20211231" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using OpenCvSharp;
using MMDeploy;
namespace object_detection
{
class Program
{
static void CvMatToMat(OpenCvSharp.Mat[] cvMats, out MMDeploy.Mat[] mats)
{
mats = new MMDeploy.Mat[cvMats.Length];
unsafe
{
for (int i = 0; i < cvMats.Length; i++)
{
mats[i].Data = cvMats[i].DataPointer;
mats[i].Height = cvMats[i].Height;
mats[i].Width = cvMats[i].Width;
mats[i].Channel = cvMats[i].Dims;
mats[i].Format = PixelFormat.BGR;
mats[i].Type = DataType.Int8;
mats[i].Device = null;
}
}
}
static void CvWaitKey()
{
Cv2.WaitKey();
}
static void Main(string[] args)
{
if (args.Length != 3)
{
Console.WriteLine("usage:\n object_detection deviceName modelPath imagePath\n");
Environment.Exit(1);
}
string deviceName = args[0];
string modelPath = args[1];
string imagePath = args[2];
// 1. create handle
RotatedDetector handle = new RotatedDetector(modelPath, deviceName, 0);
// 2. prepare input
OpenCvSharp.Mat[] imgs = new OpenCvSharp.Mat[1] { Cv2.ImRead(imagePath, ImreadModes.Color) };
CvMatToMat(imgs, out var mats);
// 3. process
List<RotatedDetectorOutput> output = handle.Apply(mats);
// 4. show result
foreach (var obj in output[0].Results)
{
if (obj.Score < 0.1)
{
continue;
}
float xc = obj.Cx;
float yc = obj.Cy;
float wx = obj.Width / 2 * (float)Math.Cos(obj.Angle);
float wy = obj.Width / 2 * (float)Math.Sin(obj.Angle);
float hx = -obj.Height / 2 * (float)Math.Sin(obj.Angle);
float hy = obj.Height / 2 * (float)Math.Cos(obj.Angle);
OpenCvSharp.Point p1 = new OpenCvSharp.Point(xc - wx - hx, yc - wy - hy);
OpenCvSharp.Point p2 = new OpenCvSharp.Point(xc + wx - hx, yc + wy - hy);
OpenCvSharp.Point p3 = new OpenCvSharp.Point(xc + wx + hx, yc + wy + hy);
OpenCvSharp.Point p4 = new OpenCvSharp.Point(xc - wx + hx, yc - wy + hy);
var contours = new OpenCvSharp.Point[1][];
contours[0] = new OpenCvSharp.Point[4] { p1, p2, p3, p4 };
Cv2.DrawContours(imgs[0], contours, -1, new Scalar(0, 255, 0), 2);
}
Cv2.NamedWindow("mmrotate", WindowFlags.GuiExpanded);
Cv2.ImShow("mmrotate", imgs[0]);
CvWaitKey();
handle.Close();
}
}
}

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MMDeployCSharp" Version="0.12.0" />
<PackageReference Include="OpenCvSharp4" Version="4.5.5.20211231" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.5.5.20211231" />
</ItemGroup>
</Project>