Skip to content

Commit da226e6

Browse files
authored
Merge pull request #2118 from shimat/codex/issue-2115-face-detector-input-size
Expose missing FaceDetectorYN APIs
2 parents 0b2a56b + b7f040f commit da226e6

4 files changed

Lines changed: 337 additions & 0 deletions

File tree

src/OpenCvSharp/Internal/PInvoke/NativeMethods/objdetect/NativeMethods_objdetect_FaceDetectorYN.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,57 @@ public static partial ExceptionStatus objdetect_FaceDetectorYN_create(
2222
int targetId,
2323
out IntPtr returnValue);
2424

25+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
26+
public static partial ExceptionStatus objdetect_FaceDetectorYN_create_buffer(
27+
IntPtr framework,
28+
IntPtr bufferModel,
29+
IntPtr bufferConfig,
30+
Size inputSize,
31+
float scoreThreshold,
32+
float nmsThreshold,
33+
int topK,
34+
int backendId,
35+
int targetId,
36+
out IntPtr returnValue);
37+
2538
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
2639
public static partial ExceptionStatus objdetect_Ptr_FaceDetectorYN_delete(IntPtr ptr);
2740

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

44+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
45+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setInputSize(
46+
OpenCvSafeHandle obj, Size inputSize);
47+
48+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
49+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getInputSize(
50+
OpenCvSafeHandle obj, out Size returnValue);
51+
52+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
53+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setScoreThreshold(
54+
OpenCvSafeHandle obj, float scoreThreshold);
55+
56+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
57+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getScoreThreshold(
58+
OpenCvSafeHandle obj, out float returnValue);
59+
60+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
61+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setNMSThreshold(
62+
OpenCvSafeHandle obj, float nmsThreshold);
63+
64+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
65+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getNMSThreshold(
66+
OpenCvSafeHandle obj, out float returnValue);
67+
68+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
69+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_setTopK(
70+
OpenCvSafeHandle obj, int topK);
71+
72+
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
73+
internal static partial ExceptionStatus objdetect_FaceDetectorYN_getTopK(
74+
OpenCvSafeHandle obj, out int returnValue);
75+
3176
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
3277
internal static partial ExceptionStatus objdetect_FaceDetectorYN_detect(
3378
OpenCvSafeHandle obj, in InputArrayProxy image, in OutputArrayProxy faces, out int returnValue);

src/OpenCvSharp/Modules/objdetect/FaceDetectorYN.cs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using OpenCvSharp.Dnn;
22
using OpenCvSharp.Internal;
3+
using OpenCvSharp.Internal.Vectors;
34

45
namespace OpenCvSharp;
56

@@ -56,6 +57,152 @@ public static FaceDetectorYN Create(
5657
return new FaceDetectorYN(smartPtr, rawPtr);
5758
}
5859

60+
/// <summary>
61+
/// Creates an instance of this class from buffers containing the model weights and configuration.
62+
/// </summary>
63+
/// <param name="framework">Name of the framework.</param>
64+
/// <param name="bufferModel">A buffer containing the binary model weights.</param>
65+
/// <param name="bufferConfig">A buffer containing the network configuration.</param>
66+
/// <param name="inputSize">The size of the input image.</param>
67+
/// <param name="scoreThreshold">The threshold to filter out bounding boxes of score smaller than the given value.</param>
68+
/// <param name="nmsThreshold">The threshold to suppress bounding boxes of IoU bigger than the given value.</param>
69+
/// <param name="topK">Keep top K bounding boxes before NMS.</param>
70+
/// <param name="backendId">The id of backend.</param>
71+
/// <param name="targetId">The id of target device.</param>
72+
public static FaceDetectorYN Create(
73+
string framework,
74+
byte[] bufferModel,
75+
byte[] bufferConfig,
76+
Size inputSize,
77+
float scoreThreshold = 0.9f,
78+
float nmsThreshold = 0.3f,
79+
int topK = 5000,
80+
Backend backendId = Backend.DEFAULT,
81+
Target targetId = Target.CPU)
82+
{
83+
ArgumentNullException.ThrowIfNull(bufferModel);
84+
ArgumentNullException.ThrowIfNull(bufferConfig);
85+
86+
using StdString csFramework = new(framework);
87+
using var bufferModelVec = new StdVector<byte>(bufferModel);
88+
using var bufferConfigVec = new StdVector<byte>(bufferConfig);
89+
90+
NativeMethods.HandleException(
91+
NativeMethods.objdetect_FaceDetectorYN_create_buffer(
92+
csFramework.CvPtr,
93+
bufferModelVec.CvPtr,
94+
bufferConfigVec.CvPtr,
95+
inputSize,
96+
scoreThreshold,
97+
nmsThreshold,
98+
topK,
99+
(int)backendId,
100+
(int)targetId,
101+
out var smartPtr));
102+
NativeMethods.HandleException(
103+
NativeMethods.objdetect_Ptr_FaceDetectorYN_get(smartPtr, out var rawPtr));
104+
return new FaceDetectorYN(smartPtr, rawPtr);
105+
}
106+
107+
/// <summary>
108+
/// Sets the network input size, overwriting the size specified when the detector was created.
109+
/// </summary>
110+
/// <param name="inputSize">The size of the input image.</param>
111+
public void SetInputSize(Size inputSize)
112+
{
113+
ThrowIfDisposed();
114+
NativeMethods.HandleException(
115+
NativeMethods.objdetect_FaceDetectorYN_setInputSize(Handle, inputSize));
116+
}
117+
118+
/// <summary>
119+
/// Sets the network input size, overwriting the size specified when the detector was created.
120+
/// </summary>
121+
/// <param name="width">The input image width.</param>
122+
/// <param name="height">The input image height.</param>
123+
public void SetInputSize(int width, int height) => SetInputSize(new Size(width, height));
124+
125+
/// <summary>
126+
/// Gets the network input size.
127+
/// </summary>
128+
/// <returns>The size of the input image.</returns>
129+
public Size GetInputSize()
130+
{
131+
ThrowIfDisposed();
132+
NativeMethods.HandleException(
133+
NativeMethods.objdetect_FaceDetectorYN_getInputSize(Handle, out var result));
134+
return result;
135+
}
136+
137+
/// <summary>
138+
/// Sets the score threshold used to filter bounding boxes.
139+
/// </summary>
140+
/// <param name="scoreThreshold">The threshold for filtering bounding boxes.</param>
141+
public void SetScoreThreshold(float scoreThreshold)
142+
{
143+
ThrowIfDisposed();
144+
NativeMethods.HandleException(
145+
NativeMethods.objdetect_FaceDetectorYN_setScoreThreshold(Handle, scoreThreshold));
146+
}
147+
148+
/// <summary>
149+
/// Gets the score threshold used to filter bounding boxes.
150+
/// </summary>
151+
/// <returns>The score threshold.</returns>
152+
public float GetScoreThreshold()
153+
{
154+
ThrowIfDisposed();
155+
NativeMethods.HandleException(
156+
NativeMethods.objdetect_FaceDetectorYN_getScoreThreshold(Handle, out var result));
157+
return result;
158+
}
159+
160+
/// <summary>
161+
/// Sets the non-maximum-suppression threshold.
162+
/// </summary>
163+
/// <param name="nmsThreshold">The threshold for NMS.</param>
164+
public void SetNMSThreshold(float nmsThreshold)
165+
{
166+
ThrowIfDisposed();
167+
NativeMethods.HandleException(
168+
NativeMethods.objdetect_FaceDetectorYN_setNMSThreshold(Handle, nmsThreshold));
169+
}
170+
171+
/// <summary>
172+
/// Gets the non-maximum-suppression threshold.
173+
/// </summary>
174+
/// <returns>The threshold for NMS.</returns>
175+
public float GetNMSThreshold()
176+
{
177+
ThrowIfDisposed();
178+
NativeMethods.HandleException(
179+
NativeMethods.objdetect_FaceDetectorYN_getNMSThreshold(Handle, out var result));
180+
return result;
181+
}
182+
183+
/// <summary>
184+
/// Sets the number of bounding boxes preserved before NMS.
185+
/// </summary>
186+
/// <param name="topK">The number of bounding boxes to preserve.</param>
187+
public void SetTopK(int topK)
188+
{
189+
ThrowIfDisposed();
190+
NativeMethods.HandleException(
191+
NativeMethods.objdetect_FaceDetectorYN_setTopK(Handle, topK));
192+
}
193+
194+
/// <summary>
195+
/// Gets the number of bounding boxes preserved before NMS.
196+
/// </summary>
197+
/// <returns>The number of bounding boxes to preserve.</returns>
198+
public int GetTopK()
199+
{
200+
ThrowIfDisposed();
201+
NativeMethods.HandleException(
202+
NativeMethods.objdetect_FaceDetectorYN_getTopK(Handle, out var result));
203+
return result;
204+
}
205+
59206
/// <summary>
60207
/// A simple interface to detect face from given image.
61208
/// </summary>

src/OpenCvSharpExtern/objdetect_FaceDetectorYN.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_create(
3232
});
3333
}
3434

35+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_create_buffer(
36+
cv::String* framework,
37+
std::vector<uchar>* bufferModel,
38+
std::vector<uchar>* bufferConfig,
39+
const interop::Size inputSize,
40+
float scoreThreshold,
41+
float nmsThreshold,
42+
int topK,
43+
int backendId,
44+
int targetId,
45+
cv::Ptr<cv::FaceDetectorYN>** returnValue)
46+
{
47+
return cvTry([&] {
48+
const auto p = cv::FaceDetectorYN::create(
49+
*framework, *bufferModel, *bufferConfig, cpp(inputSize),
50+
scoreThreshold, nmsThreshold, topK,
51+
backendId, targetId);
52+
*returnValue = clone(p);
53+
});
54+
}
55+
3556
CVAPI(ExceptionStatus) objdetect_Ptr_FaceDetectorYN_delete(cv::Ptr<cv::FaceDetectorYN>* ptr)
3657
{
3758
return cvTry([&] {
@@ -46,6 +67,78 @@ CVAPI(ExceptionStatus) objdetect_Ptr_FaceDetectorYN_get(cv::Ptr<cv::FaceDetector
4667
});
4768
}
4869

70+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setInputSize(
71+
cv::FaceDetectorYN* obj,
72+
const interop::Size inputSize)
73+
{
74+
return cvTry([&] {
75+
obj->setInputSize(cpp(inputSize));
76+
});
77+
}
78+
79+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getInputSize(
80+
cv::FaceDetectorYN* obj,
81+
interop::Size* returnValue)
82+
{
83+
return cvTry([&] {
84+
*returnValue = c(obj->getInputSize());
85+
});
86+
}
87+
88+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setScoreThreshold(
89+
cv::FaceDetectorYN* obj,
90+
float scoreThreshold)
91+
{
92+
return cvTry([&] {
93+
obj->setScoreThreshold(scoreThreshold);
94+
});
95+
}
96+
97+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getScoreThreshold(
98+
cv::FaceDetectorYN* obj,
99+
float* returnValue)
100+
{
101+
return cvTry([&] {
102+
*returnValue = obj->getScoreThreshold();
103+
});
104+
}
105+
106+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setNMSThreshold(
107+
cv::FaceDetectorYN* obj,
108+
float nmsThreshold)
109+
{
110+
return cvTry([&] {
111+
obj->setNMSThreshold(nmsThreshold);
112+
});
113+
}
114+
115+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getNMSThreshold(
116+
cv::FaceDetectorYN* obj,
117+
float* returnValue)
118+
{
119+
return cvTry([&] {
120+
*returnValue = obj->getNMSThreshold();
121+
});
122+
}
123+
124+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_setTopK(
125+
cv::FaceDetectorYN* obj,
126+
int topK)
127+
{
128+
return cvTry([&] {
129+
obj->setTopK(topK);
130+
});
131+
}
132+
133+
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_getTopK(
134+
cv::FaceDetectorYN* obj,
135+
int* returnValue)
136+
{
137+
return cvTry([&] {
138+
*returnValue = obj->getTopK();
139+
});
140+
}
141+
49142
CVAPI(ExceptionStatus) objdetect_FaceDetectorYN_detect(
50143
cv::FaceDetectorYN* obj,
51144
const interop::InputArrayProxy* image,

test/OpenCvSharp.Tests/objdetect/FaceDetectorYNTest.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,58 @@ public void CreateWithParameters()
4949
Assert.NotNull(detector);
5050
}
5151

52+
[Fact]
53+
public void CreateFromBuffer()
54+
{
55+
var model = File.ReadAllBytes(ModelPath);
56+
57+
using var detector = FaceDetectorYN.Create(
58+
framework: "onnx",
59+
bufferModel: model,
60+
bufferConfig: Array.Empty<byte>(),
61+
inputSize: new Size(320, 320));
62+
63+
Assert.NotNull(detector);
64+
}
65+
66+
[Fact]
67+
public void SetInputSize()
68+
{
69+
using var image = LoadImage("lenna.png");
70+
using var detector = FaceDetectorYN.Create(
71+
ModelPath,
72+
config: "",
73+
inputSize: new Size(320, 320));
74+
75+
detector.SetInputSize(image.Width, image.Height);
76+
77+
using var faces = new Mat();
78+
Assert.Equal(1, detector.Detect(image, faces));
79+
Assert.False(faces.Empty());
80+
}
81+
82+
[Fact]
83+
public void GetAndSetParameters()
84+
{
85+
using var detector = FaceDetectorYN.Create(
86+
ModelPath,
87+
config: "",
88+
inputSize: new Size(320, 320));
89+
90+
Assert.Equal(new Size(320, 320), detector.GetInputSize());
91+
detector.SetInputSize(640, 480);
92+
Assert.Equal(new Size(640, 480), detector.GetInputSize());
93+
94+
detector.SetScoreThreshold(0.75f);
95+
Assert.Equal(0.75f, detector.GetScoreThreshold());
96+
97+
detector.SetNMSThreshold(0.4f);
98+
Assert.Equal(0.4f, detector.GetNMSThreshold());
99+
100+
detector.SetTopK(3000);
101+
Assert.Equal(3000, detector.GetTopK());
102+
}
103+
52104
[Fact]
53105
public void DisposeTwice()
54106
{

0 commit comments

Comments
 (0)