Skip to content

Commit d74b74a

Browse files
authored
Merge pull request #2125 from shimat/fix/issue-2124-double-inputarray
Fix double InputArray multi-channel semantics
2 parents dfc6f86 + 85d5f5c commit d74b74a

3 files changed

Lines changed: 34 additions & 11 deletions

File tree

src/OpenCvSharp/Modules/core/InputArray.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public enum ArrayProxyKind
2727
MatExpr = 3,
2828
/// <summary>A <see cref="Scalar"/> value (inline).</summary>
2929
Scalar = 4,
30-
/// <summary>A scalar <see cref="double"/> value (inline, as Scalar(d,0,0,0)).</summary>
30+
/// <summary>A scalar <see cref="double"/> value (inline, as a 1x1 CV_64F input).</summary>
3131
Double = 5,
3232
/// <summary>A small fixed-length vector value (inline).</summary>
3333
Vec = 6,
@@ -137,7 +137,7 @@ public static implicit operator InputArray(MatExpr expr)
137137
public static implicit operator InputArray(Scalar s) =>
138138
new(null, InputArrayProxy.FromScalar(s));
139139

140-
/// <summary>Wraps a <see cref="double"/> value (no allocation; travels inline as Scalar(d,0,0,0)).</summary>
140+
/// <summary>Wraps a <see cref="double"/> value (no allocation; travels inline as a 1x1 CV_64F input).</summary>
141141
public static implicit operator InputArray(double d) =>
142142
new(null, new InputArrayProxy { Kind = (int)ArrayProxyKind.Double, Payload0 = d });
143143

src/OpenCvSharpExtern/my_types.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -423,11 +423,10 @@ static cv::Moments cpp(const interop::Moments &m)
423423
// no heap cv::_InputArray is allocated per call. Use the InProxy/OutProxy/IoProxy
424424
// views below at the head of a CVAPI body.
425425
//
426-
// Scalar/Double inputs: cv::_InputArray references a cv::Scalar, so the caller must
427-
// keep `scalarScratch` alive for the whole OpenCV call (one scratch per input that
428-
// may be a scalar).
429-
// Vec inputs: cv::_InputArray references proxy.payload; the by-value parameter copy
430-
// stays valid for the call.
426+
// Scalar inputs: cv::_InputArray references a cv::Scalar, so the caller must keep
427+
// `scalarScratch` alive for the whole OpenCV call (one scratch per scalar input).
428+
// Double/Vec inputs: cv::_InputArray references proxy.payload; the proxy stays valid
429+
// for the call.
431430
// -------------------------------------------------------------------------
432431
static cv::_InputArray fromInputProxy(const interop::InputArrayProxy &p, cv::Scalar &scalarScratch)
433432
{
@@ -437,9 +436,9 @@ static cv::_InputArray fromInputProxy(const interop::InputArrayProxy &p, cv::Sca
437436
case 2: return cv::_InputArray(*static_cast<cv::UMat *>(p.handle));
438437
case 3: return cv::_InputArray(*static_cast<cv::MatExpr *>(p.handle));
439438
case 4:
440-
case 5:
441439
scalarScratch = cv::Scalar(p.payload[0], p.payload[1], p.payload[2], p.payload[3]);
442440
return cv::_InputArray(scalarScratch);
441+
case 5: return cv::_InputArray(p.payload[0]);
443442
case 6:
444443
switch (p.vecDepth)
445444
{
@@ -493,10 +492,10 @@ static cv::_InputOutputArray fromInputOutputProxy(const interop::InputOutputArra
493492
class InProxy
494493
{
495494
// Stable storage for a scalar operand. A cv::_InputArray built from a cv::Scalar keeps a POINTER
496-
// to that Scalar (it does not copy it), so the Scalar must outlive the _InputArray's use. For
497-
// Scalar/Double kinds fromInputProxy() writes scratch_ and returns a cv::_InputArray referencing
495+
// to that Scalar (it does not copy it), so the Scalar must outlive the _InputArray's use.
496+
// For the Scalar kind, fromInputProxy() writes scratch_ and returns a cv::_InputArray referencing
498497
// it; holding scratch_ as a member keeps it alive for the whole OpenCV call (the InProxy lives to
499-
// the end of the call expression). Unused for Mat/UMat/MatExpr/Vec/Raw kinds.
498+
// the end of the call expression). Unused for Mat/UMat/MatExpr/Double/Vec/Raw kinds.
500499
cv::Scalar scratch_;
501500
cv::_InputArray ia_;
502501
public:

test/OpenCvSharp.Tests/core/InputArrayTest.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,30 @@ public void Add_MatPlusScalar_IsAllocationFree()
5252
Assert.Equal(0, after - before);
5353
}
5454

55+
[Fact]
56+
public void DoubleAndScalar_PreserveDistinctMultiChannelSemantics()
57+
{
58+
using var src = new Mat(1, 1, MatType.CV_64FC4, Scalar.All(10));
59+
60+
using var fromDouble = new Mat();
61+
Cv2.Add(src, 5.0, fromDouble);
62+
Assert.Equal(new Vec4d(15, 15, 15, 15), fromDouble.At<Vec4d>(0, 0));
63+
64+
using var fromScalar = new Mat();
65+
Cv2.Add(src, new Scalar(5), fromScalar);
66+
Assert.Equal(new Vec4d(15, 10, 10, 10), fromScalar.At<Vec4d>(0, 0));
67+
}
68+
69+
[Fact]
70+
public void Randu_DoubleBoundsBroadcastAcrossChannels()
71+
{
72+
using var mat = new Mat(1, 1, MatType.CV_8UC4);
73+
74+
Cv2.Randu(mat, 100, 101);
75+
76+
Assert.Equal(new Vec4b(100, 100, 100, 100), mat.At<Vec4b>(0, 0));
77+
}
78+
5579
[Fact]
5680
public void Transpose_Vec_IsAllocationFree()
5781
{

0 commit comments

Comments
 (0)