[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 defaultpull/1828/head
parent
7fed511f09
commit
7de413a19c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -99,7 +99,7 @@ namespace MMDeploy
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output of DetectorOutput.
|
||||
/// Output of TextDetector.
|
||||
/// </summary>
|
||||
public struct TextDetectorOutput
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
Loading…
Reference in New Issue