-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
FeaturesMatcher.cs
194 lines (179 loc) · 6.91 KB
/
FeaturesMatcher.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
using OpenCvSharp.Internal;
using OpenCvSharp.Internal.Util;
using OpenCvSharp.Internal.Vectors;
namespace OpenCvSharp.Detail;
/// <summary>
/// Feature matchers base class.
/// </summary>
public abstract class FeaturesMatcher : DisposableCvObject
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="ptr"></param>
protected FeaturesMatcher(IntPtr ptr)
: base(ptr)
{
}
/// <summary>
/// Performs images matching.
/// </summary>
/// <param name="features1">First image features</param>
/// <param name="features2">Second image features</param>
/// <returns>Found matches</returns>
public virtual MatchesInfo Apply(
ImageFeatures features1, ImageFeatures features2)
{
ThrowIfDisposed();
if (features1 is null)
throw new ArgumentNullException(nameof(features1));
if (features2 is null)
throw new ArgumentNullException(nameof(features2));
if (features1.Descriptors is null)
throw new ArgumentException($"{nameof(features1)}.Descriptors is null", nameof(features1));
if (features2.Descriptors is null)
throw new ArgumentException($"{nameof(features2)}.Descriptors is null", nameof(features1));
features1.Descriptors.ThrowIfDisposed();
features2.Descriptors.ThrowIfDisposed();
using var keypointsVec1 = new VectorOfKeyPoint(features1.Keypoints);
using var keypointsVec2 = new VectorOfKeyPoint(features2.Keypoints);
var features1Cpp = new WImageFeatures
{
ImgIdx = features1.ImgIdx,
ImgSize = features1.ImgSize,
Keypoints = keypointsVec1.CvPtr,
Descriptors = features1.Descriptors.CvPtr,
};
var features2Cpp = new WImageFeatures
{
ImgIdx = features2.ImgIdx,
ImgSize = features2.ImgSize,
Keypoints = keypointsVec2.CvPtr,
Descriptors = features2.Descriptors.CvPtr,
};
using var matchesVec = new VectorOfDMatch();
using var inliersMaskVec = new VectorOfByte();
var h = new Mat();
NativeMethods.HandleException(
NativeMethods.stitching_FeaturesMatcher_apply(
ptr,
ref features1Cpp,
ref features2Cpp,
out var srcImgIdx,
out var dstImgIdx,
matchesVec.CvPtr,
inliersMaskVec.CvPtr,
out var numInliers,
h.CvPtr,
out var confidence));
GC.KeepAlive(this);
return new MatchesInfo(
srcImgIdx, dstImgIdx, matchesVec.ToArray(), inliersMaskVec.ToArray(),
numInliers, h, confidence);
}
/// <summary>
/// Performs images matching.
/// </summary>
/// <param name="features">Features of the source images</param>
/// <param name="mask">Mask indicating which image pairs must be matched</param>
/// <returns>Found pairwise matches</returns>
public virtual MatchesInfo[] Apply(
IEnumerable<ImageFeatures> features, Mat? mask = null)
{
if (features is null)
throw new ArgumentNullException(nameof(features));
ThrowIfDisposed();
var featuresArray = features.CastOrToArray();
if (featuresArray.Length == 0)
throw new ArgumentException("Empty features array", nameof(features));
var keypointVecs = new VectorOfKeyPoint?[featuresArray.Length];
var wImageFeatures = new WImageFeatures[featuresArray.Length];
try
{
for (int i = 0; i < featuresArray.Length; i++)
{
if (featuresArray[i].Descriptors is null)
throw new ArgumentException("features contain null descriptor mat", nameof(features));
featuresArray[i].Descriptors.ThrowIfDisposed();
keypointVecs[i] = new VectorOfKeyPoint();
wImageFeatures[i] = new WImageFeatures
{
ImgIdx = featuresArray[i].ImgIdx,
ImgSize = featuresArray[i].ImgSize,
Keypoints = keypointVecs[i]!.CvPtr,
Descriptors = featuresArray[i].Descriptors.CvPtr,
};
}
using var srcImgIndexVecs = new VectorOfInt32();
using var dstImgIndexVecs = new VectorOfInt32();
using var matchesVec = new VectorOfVectorDMatch();
using var inlinersMaskVec = new VectorOfVectorByte();
using var numInliersVecs = new VectorOfInt32();
using var hVecs = new VectorOfMat();
using var confidenceVecs = new VectorOfDouble();
NativeMethods.HandleException(
NativeMethods.stitching_FeaturesMatcher_apply2(
ptr,
wImageFeatures, wImageFeatures.Length,
mask?.CvPtr ?? IntPtr.Zero,
srcImgIndexVecs.CvPtr,
dstImgIndexVecs.CvPtr,
matchesVec.CvPtr,
inlinersMaskVec.CvPtr,
numInliersVecs.CvPtr,
hVecs.CvPtr,
confidenceVecs.CvPtr
));
var srcImgIndices = srcImgIndexVecs.ToArray();
var dstImgIndices = dstImgIndexVecs.ToArray();
var matches = matchesVec.ToArray();
var inlinersMasks = inlinersMaskVec.ToArray();
var numInliers = numInliersVecs.ToArray();
var hs = hVecs.ToArray();
var confidences = confidenceVecs.ToArray();
var result = new MatchesInfo[srcImgIndices.Length];
for (int i = 0; i < srcImgIndices.Length; i++)
{
result[i] = new MatchesInfo(
srcImgIndices[i],
dstImgIndices[i],
matches[i],
inlinersMasks[i],
numInliers[i],
hs[i],
confidences[i]);
}
return result;
}
finally
{
foreach (var vec in keypointVecs)
{
vec?.Dispose();
}
GC.KeepAlive(this);
}
}
/// <summary>
/// True, if it's possible to use the same matcher instance in parallel, false otherwise
/// </summary>
/// <returns></returns>
public virtual bool IsThreadSafe()
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.stitching_FeaturesMatcher_isThreadSafe(ptr, out var ret));
GC.KeepAlive(this);
return ret != 0;
}
/// <summary>
/// Frees unused memory allocated before if there is any.
/// </summary>
public virtual void CollectGarbage()
{
ThrowIfDisposed();
NativeMethods.HandleException(
NativeMethods.stitching_FeaturesMatcher_collectGarbage(ptr));
GC.KeepAlive(this);
}
}