Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,57 @@ public static partial ExceptionStatus objdetect_FaceDetectorYN_create(
int targetId,
out IntPtr returnValue);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial ExceptionStatus objdetect_FaceDetectorYN_create_buffer(
IntPtr framework,
IntPtr bufferModel,
IntPtr bufferConfig,
Size inputSize,
float scoreThreshold,
float nmsThreshold,
int topK,
int backendId,
int targetId,
out IntPtr returnValue);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial ExceptionStatus objdetect_Ptr_FaceDetectorYN_delete(IntPtr ptr);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial ExceptionStatus objdetect_Ptr_FaceDetectorYN_get(IntPtr ptr, out IntPtr returnValue);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setInputSize(
OpenCvSafeHandle obj, Size inputSize);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getInputSize(
OpenCvSafeHandle obj, out Size returnValue);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setScoreThreshold(
OpenCvSafeHandle obj, float scoreThreshold);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getScoreThreshold(
OpenCvSafeHandle obj, out float returnValue);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setNMSThreshold(
OpenCvSafeHandle obj, float nmsThreshold);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getNMSThreshold(
OpenCvSafeHandle obj, out float returnValue);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setTopK(
OpenCvSafeHandle obj, int topK);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getTopK(
OpenCvSafeHandle obj, out int returnValue);

[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ExceptionStatus objdetect_FaceDetectorYN_detect(
OpenCvSafeHandle obj, in InputArrayProxy image, in OutputArrayProxy faces, out int returnValue);
Expand Down
147 changes: 147 additions & 0 deletions src/OpenCvSharp/Modules/objdetect/FaceDetectorYN.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using OpenCvSharp.Dnn;
using OpenCvSharp.Internal;
using OpenCvSharp.Internal.Vectors;

namespace OpenCvSharp;

Expand Down Expand Up @@ -56,6 +57,152 @@ public static FaceDetectorYN Create(
return new FaceDetectorYN(smartPtr, rawPtr);
}

/// <summary>
/// Creates an instance of this class from buffers containing the model weights and configuration.
/// </summary>
/// <param name="framework">Name of the framework.</param>
/// <param name="bufferModel">A buffer containing the binary model weights.</param>
/// <param name="bufferConfig">A buffer containing the network configuration.</param>
/// <param name="inputSize">The size of the input image.</param>
/// <param name="scoreThreshold">The threshold to filter out bounding boxes of score smaller than the given value.</param>
/// <param name="nmsThreshold">The threshold to suppress bounding boxes of IoU bigger than the given value.</param>
/// <param name="topK">Keep top K bounding boxes before NMS.</param>
/// <param name="backendId">The id of backend.</param>
/// <param name="targetId">The id of target device.</param>
public static FaceDetectorYN Create(
string framework,
byte[] bufferModel,
byte[] bufferConfig,
Size inputSize,
float scoreThreshold = 0.9f,
float nmsThreshold = 0.3f,
int topK = 5000,
Backend backendId = Backend.DEFAULT,
Target targetId = Target.CPU)
{
ArgumentNullException.ThrowIfNull(bufferModel);
ArgumentNullException.ThrowIfNull(bufferConfig);

using StdString csFramework = new(framework);
using var bufferModelVec = new StdVector<byte>(bufferModel);
using var bufferConfigVec = new StdVector<byte>(bufferConfig);

NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_create_buffer(
csFramework.CvPtr,
bufferModelVec.CvPtr,
bufferConfigVec.CvPtr,
inputSize,
scoreThreshold,
nmsThreshold,
topK,
(int)backendId,
(int)targetId,
out var smartPtr));
NativeMethods.HandleException(
NativeMethods.objdetect_Ptr_FaceDetectorYN_get(smartPtr, out var rawPtr));
return new FaceDetectorYN(smartPtr, rawPtr);
}

/// <summary>
/// Sets the network input size, overwriting the size specified when the detector was created.
/// </summary>
/// <param name="inputSize">The size of the input image.</param>
public void SetInputSize(Size inputSize)
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_setInputSize(Handle, inputSize));
}

/// <summary>
/// Sets the network input size, overwriting the size specified when the detector was created.
/// </summary>
/// <param name="width">The input image width.</param>
/// <param name="height">The input image height.</param>
public void SetInputSize(int width, int height) => SetInputSize(new Size(width, height));

/// <summary>
/// Gets the network input size.
/// </summary>
/// <returns>The size of the input image.</returns>
public Size GetInputSize()
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_getInputSize(Handle, out var result));
return result;
}

/// <summary>
/// Sets the score threshold used to filter bounding boxes.
/// </summary>
/// <param name="scoreThreshold">The threshold for filtering bounding boxes.</param>
public void SetScoreThreshold(float scoreThreshold)
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_setScoreThreshold(Handle, scoreThreshold));
}

/// <summary>
/// Gets the score threshold used to filter bounding boxes.
/// </summary>
/// <returns>The score threshold.</returns>
public float GetScoreThreshold()
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_getScoreThreshold(Handle, out var result));
return result;
}

/// <summary>
/// Sets the non-maximum-suppression threshold.
/// </summary>
/// <param name="nmsThreshold">The threshold for NMS.</param>
public void SetNMSThreshold(float nmsThreshold)
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_setNMSThreshold(Handle, nmsThreshold));
}

/// <summary>
/// Gets the non-maximum-suppression threshold.
/// </summary>
/// <returns>The threshold for NMS.</returns>
public float GetNMSThreshold()
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_getNMSThreshold(Handle, out var result));
return result;
}

/// <summary>
/// Sets the number of bounding boxes preserved before NMS.
/// </summary>
/// <param name="topK">The number of bounding boxes to preserve.</param>
public void SetTopK(int topK)
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_setTopK(Handle, topK));
}

/// <summary>
/// Gets the number of bounding boxes preserved before NMS.
/// </summary>
/// <returns>The number of bounding boxes to preserve.</returns>
public int GetTopK()
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.objdetect_FaceDetectorYN_getTopK(Handle, out var result));
return result;
}

/// <summary>
/// A simple interface to detect face from given image.
/// </summary>
Expand Down
93 changes: 93 additions & 0 deletions src/OpenCvSharpExtern/objdetect_FaceDetectorYN.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@ CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_create(
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_create_buffer(
cv::String* framework,
std::vector<uchar>* bufferModel,
std::vector<uchar>* bufferConfig,
const interop::Size inputSize,
float scoreThreshold,
float nmsThreshold,
int topK,
int backendId,
int targetId,
cv::Ptr<cv::FaceDetectorYN>** returnValue)
{
return cvTry([&] {
const auto p = cv::FaceDetectorYN::create(
*framework, *bufferModel, *bufferConfig, cpp(inputSize),
scoreThreshold, nmsThreshold, topK,
backendId, targetId);
*returnValue = clone(p);
});
}

CVAPI(ExceptionStatus) objdetect_Ptr_FaceDetectorYN_delete(cv::Ptr<cv::FaceDetectorYN>* ptr)
{
return cvTry([&] {
Expand All @@ -46,6 +67,78 @@ CVAPI(ExceptionStatus) objdetect_Ptr_FaceDetectorYN_get(cv::Ptr<cv::FaceDetector
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setInputSize(
cv::FaceDetectorYN* obj,
const interop::Size inputSize)
{
return cvTry([&] {
obj->setInputSize(cpp(inputSize));
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getInputSize(
cv::FaceDetectorYN* obj,
interop::Size* returnValue)
{
return cvTry([&] {
*returnValue = c(obj->getInputSize());
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setScoreThreshold(
cv::FaceDetectorYN* obj,
float scoreThreshold)
{
return cvTry([&] {
obj->setScoreThreshold(scoreThreshold);
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getScoreThreshold(
cv::FaceDetectorYN* obj,
float* returnValue)
{
return cvTry([&] {
*returnValue = obj->getScoreThreshold();
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setNMSThreshold(
cv::FaceDetectorYN* obj,
float nmsThreshold)
{
return cvTry([&] {
obj->setNMSThreshold(nmsThreshold);
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getNMSThreshold(
cv::FaceDetectorYN* obj,
float* returnValue)
{
return cvTry([&] {
*returnValue = obj->getNMSThreshold();
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setTopK(
cv::FaceDetectorYN* obj,
int topK)
{
return cvTry([&] {
obj->setTopK(topK);
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getTopK(
cv::FaceDetectorYN* obj,
int* returnValue)
{
return cvTry([&] {
*returnValue = obj->getTopK();
});
}

CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_detect(
cv::FaceDetectorYN* obj,
const interop::InputArrayProxy* image,
Expand Down
52 changes: 52 additions & 0 deletions test/OpenCvSharp.Tests/objdetect/FaceDetectorYNTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,58 @@ public void CreateWithParameters()
Assert.NotNull(detector);
}

[Fact]
public void CreateFromBuffer()
{
var model = File.ReadAllBytes(ModelPath);

using var detector = FaceDetectorYN.Create(
framework: "onnx",
bufferModel: model,
bufferConfig: Array.Empty<byte>(),
inputSize: new Size(320, 320));

Assert.NotNull(detector);
}

[Fact]
public void SetInputSize()
{
using var image = LoadImage("lenna.png");
using var detector = FaceDetectorYN.Create(
ModelPath,
config: "",
inputSize: new Size(320, 320));

detector.SetInputSize(image.Width, image.Height);

using var faces = new Mat();
Assert.Equal(1, detector.Detect(image, faces));
Assert.False(faces.Empty());
}

[Fact]
public void GetAndSetParameters()
{
using var detector = FaceDetectorYN.Create(
ModelPath,
config: "",
inputSize: new Size(320, 320));

Assert.Equal(new Size(320, 320), detector.GetInputSize());
detector.SetInputSize(640, 480);
Assert.Equal(new Size(640, 480), detector.GetInputSize());

detector.SetScoreThreshold(0.75f);
Assert.Equal(0.75f, detector.GetScoreThreshold());

detector.SetNMSThreshold(0.4f);
Assert.Equal(0.4f, detector.GetNMSThreshold());

detector.SetTopK(3000);
Assert.Equal(3000, detector.GetTopK());
}

[Fact]
public void DisposeTwice()
{
Expand Down
Loading