Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
8a178da1
Commit
8a178da1
authored
Jan 13, 2015
by
Vladislav Vinogradov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor CUDA BFMatcher algorithm:
use new abstract interface and hidden implementation
parent
764d55b8
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1121 additions
and
905 deletions
+1121
-905
cudafeatures2d.hpp
modules/cudafeatures2d/include/opencv2/cudafeatures2d.hpp
+304
-159
perf_features2d.cpp
modules/cudafeatures2d/perf/perf_features2d.cpp
+12
-12
brute_force_matcher.cpp
modules/cudafeatures2d/src/brute_force_matcher.cpp
+754
-688
test_features2d.cpp
modules/cudafeatures2d/test/test_features2d.cpp
+38
-30
matchers.cpp
modules/stitching/src/matchers.cpp
+5
-6
tests.cpp
samples/gpu/performance/tests.cpp
+8
-10
No files found.
modules/cudafeatures2d/include/opencv2/cudafeatures2d.hpp
View file @
8a178da1
...
@@ -63,170 +63,315 @@ namespace cv { namespace cuda {
...
@@ -63,170 +63,315 @@ namespace cv { namespace cuda {
//! @addtogroup cudafeatures2d
//! @addtogroup cudafeatures2d
//! @{
//! @{
/** @brief Brute-force descriptor matcher.
//
// DescriptorMatcher
For each descriptor in the first set, this matcher finds the closest descriptor in the second set
//
by trying each one. This descriptor matcher supports masking permissible matches between descriptor
sets.
The class BFMatcher_CUDA has an interface similar to the class DescriptorMatcher. It has two groups
/** @brief Abstract base class for matching keypoint descriptors.
of match methods: for matching descriptors of one image with another image or with an image set.
Also, all functions have an alternative to save results either to the GPU memory or to the CPU
memory.
@sa DescriptorMatcher, BFMatcher
It has two groups of match methods: for matching descriptors of an image with another image or with
an image set.
*/
*/
class
CV_EXPORTS
BFMatcher_CUDA
class
CV_EXPORTS
DescriptorMatcher
:
public
cv
::
Algorithm
{
{
public
:
public
:
explicit
BFMatcher_CUDA
(
int
norm
=
cv
::
NORM_L2
);
//
// Factories
//! Add descriptors to train descriptor collection
//
void
add
(
const
std
::
vector
<
GpuMat
>&
descCollection
);
/** @brief Brute-force descriptor matcher.
//! Get train descriptors collection
const
std
::
vector
<
GpuMat
>&
getTrainDescriptors
()
const
;
For each descriptor in the first set, this matcher finds the closest descriptor in the second set
by trying each one. This descriptor matcher supports masking permissible matches of descriptor
//! Clear train descriptors collection
sets.
void
clear
();
@param normType One of NORM_L1, NORM_L2, NORM_HAMMING. L1 and L2 norms are
//! Return true if there are not train descriptors in collection
preferable choices for SIFT and SURF descriptors, NORM_HAMMING should be used with ORB, BRISK and
bool
empty
()
const
;
BRIEF).
*/
//! Return true if the matcher supports mask in match methods
static
Ptr
<
DescriptorMatcher
>
createBFMatcher
(
int
norm
=
cv
::
NORM_L2
);
bool
isMaskSupported
()
const
;
//
//! Find one best match for each query descriptor
// Utility
void
matchSingle
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
//
GpuMat
&
trainIdx
,
GpuMat
&
distance
,
const
GpuMat
&
mask
=
GpuMat
(),
Stream
&
stream
=
Stream
::
Null
());
/** @brief Returns true if the descriptor matcher supports masking permissible matches.
*/
//! Download trainIdx and distance and convert it to CPU vector with DMatch
virtual
bool
isMaskSupported
()
const
=
0
;
static
void
matchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
distance
,
std
::
vector
<
DMatch
>&
matches
);
//! Convert trainIdx and distance to vector with DMatch
//
static
void
matchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
distance
,
std
::
vector
<
DMatch
>&
matches
);
// Descriptor collection
//
//! Find one best match for each query descriptor
void
match
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
std
::
vector
<
DMatch
>&
matches
,
const
GpuMat
&
mask
=
GpuMat
());
/** @brief Adds descriptors to train a descriptor collection.
//! Make gpu collection of trains and masks in suitable format for matchCollection function
If the collection is not empty, the new descriptors are added to existing train descriptors.
void
makeGpuCollection
(
GpuMat
&
trainCollection
,
GpuMat
&
maskCollection
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
());
@param descriptors Descriptors to add. Each descriptors[i] is a set of descriptors from the same
//! Find one best match from train collection for each query descriptor
train image.
void
matchCollection
(
const
GpuMat
&
query
,
const
GpuMat
&
trainCollection
,
*/
GpuMat
&
trainIdx
,
GpuMat
&
imgIdx
,
GpuMat
&
distance
,
virtual
void
add
(
const
std
::
vector
<
GpuMat
>&
descriptors
)
=
0
;
const
GpuMat
&
masks
=
GpuMat
(),
Stream
&
stream
=
Stream
::
Null
());
/** @brief Returns a constant link to the train descriptor collection.
//! Download trainIdx, imgIdx and distance and convert it to vector with DMatch
*/
static
void
matchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
imgIdx
,
const
GpuMat
&
distance
,
std
::
vector
<
DMatch
>&
matches
);
virtual
const
std
::
vector
<
GpuMat
>&
getTrainDescriptors
()
const
=
0
;
//! Convert trainIdx, imgIdx and distance to vector with DMatch
static
void
matchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
imgIdx
,
const
Mat
&
distance
,
std
::
vector
<
DMatch
>&
matches
);
/** @brief Clears the train descriptor collection.
*/
//! Find one best match from train collection for each query descriptor.
virtual
void
clear
()
=
0
;
void
match
(
const
GpuMat
&
query
,
std
::
vector
<
DMatch
>&
matches
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
());
/** @brief Returns true if there are no train descriptors in the collection.
//! Find k best matches for each query descriptor (in increasing order of distances)
*/
void
knnMatchSingle
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
virtual
bool
empty
()
const
=
0
;
GpuMat
&
trainIdx
,
GpuMat
&
distance
,
GpuMat
&
allDist
,
int
k
,
const
GpuMat
&
mask
=
GpuMat
(),
Stream
&
stream
=
Stream
::
Null
());
/** @brief Trains a descriptor matcher.
//! Download trainIdx and distance and convert it to vector with DMatch
Trains a descriptor matcher (for example, the flann index). In all methods to match, the method
//! compactResult is used when mask is not empty. If compactResult is false matches
train() is run every time before matching.
//! vector will have the same size as queryDescriptors rows. If compactResult is true
*/
//! matches vector will not contain matches for fully masked out query descriptors.
virtual
void
train
()
=
0
;
static
void
knnMatchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
distance
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
//
//! Convert trainIdx and distance to vector with DMatch
// 1 to 1 match
static
void
knnMatchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
distance
,
//
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
/** @brief Finds the best match for each descriptor from a query set (blocking version).
//! Find k best matches for each query descriptor (in increasing order of distances).
//! compactResult is used when mask is not empty. If compactResult is false matches
@param queryDescriptors Query set of descriptors.
//! vector will have the same size as queryDescriptors rows. If compactResult is true
@param trainDescriptors Train set of descriptors. This set is not added to the train descriptors
//! matches vector will not contain matches for fully masked out query descriptors.
collection stored in the class object.
void
knnMatch
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
@param matches Matches. If a query descriptor is masked out in mask , no match is added for this
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
const
GpuMat
&
mask
=
GpuMat
(),
descriptor. So, matches size may be smaller than the query descriptors count.
bool
compactResult
=
false
);
@param mask Mask specifying permissible matches between an input query and train matrices of
descriptors.
//! Find k best matches from train collection for each query descriptor (in increasing order of distances)
void
knnMatch2Collection
(
const
GpuMat
&
query
,
const
GpuMat
&
trainCollection
,
In the first variant of this method, the train descriptors are passed as an input argument. In the
GpuMat
&
trainIdx
,
GpuMat
&
imgIdx
,
GpuMat
&
distance
,
second variant of the method, train descriptors collection that was set by DescriptorMatcher::add is
const
GpuMat
&
maskCollection
=
GpuMat
(),
Stream
&
stream
=
Stream
::
Null
());
used. Optional mask (or masks) can be passed to specify which query and training descriptors can be
matched. Namely, queryDescriptors[i] can be matched with trainDescriptors[j] only if
//! Download trainIdx and distance and convert it to vector with DMatch
mask.at\<uchar\>(i,j) is non-zero.
//! compactResult is used when mask is not empty. If compactResult is false matches
*/
//! vector will have the same size as queryDescriptors rows. If compactResult is true
virtual
void
match
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
//! matches vector will not contain matches for fully masked out query descriptors.
std
::
vector
<
DMatch
>&
matches
,
//! @see BFMatcher_CUDA::knnMatchDownload
InputArray
mask
=
noArray
())
=
0
;
static
void
knnMatch2Download
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
imgIdx
,
const
GpuMat
&
distance
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
/** @overload
//! Convert trainIdx and distance to vector with DMatch
*/
//! @see BFMatcher_CUDA::knnMatchConvert
virtual
void
match
(
InputArray
queryDescriptors
,
static
void
knnMatch2Convert
(
const
Mat
&
trainIdx
,
const
Mat
&
imgIdx
,
const
Mat
&
distance
,
std
::
vector
<
DMatch
>&
matches
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
())
=
0
;
//! Find k best matches for each query descriptor (in increasing order of distances).
/** @brief Finds the best match for each descriptor from a query set (asynchronous version).
//! compactResult is used when mask is not empty. If compactResult is false matches
//! vector will have the same size as queryDescriptors rows. If compactResult is true
@param queryDescriptors Query set of descriptors.
//! matches vector will not contain matches for fully masked out query descriptors.
@param trainDescriptors Train set of descriptors. This set is not added to the train descriptors
void
knnMatch
(
const
GpuMat
&
query
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
collection stored in the class object.
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
bool
compactResult
=
false
);
@param matches Matches array stored in GPU memory. Internal representation is not defined.
Use DescriptorMatcher::matchConvert method to retrieve results in standard representation.
//! Find best matches for each query descriptor which have distance less than maxDistance.
@param mask Mask specifying permissible matches between an input query and train matrices of
//! nMatches.at<int>(0, queryIdx) will contain matches count for queryIdx.
descriptors.
//! carefully nMatches can be greater than trainIdx.cols - it means that matcher didn't find all matches,
@param stream CUDA stream.
//! because it didn't have enough memory.
//! If trainIdx is empty, then trainIdx and distance will be created with size nQuery x max((nTrain / 100), 10),
In the first variant of this method, the train descriptors are passed as an input argument. In the
//! otherwize user can pass own allocated trainIdx and distance with size nQuery x nMaxMatches
second variant of the method, train descriptors collection that was set by DescriptorMatcher::add is
//! Matches doesn't sorted.
used. Optional mask (or masks) can be passed to specify which query and training descriptors can be
void
radiusMatchSingle
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
matched. Namely, queryDescriptors[i] can be matched with trainDescriptors[j] only if
GpuMat
&
trainIdx
,
GpuMat
&
distance
,
GpuMat
&
nMatches
,
float
maxDistance
,
mask.at\<uchar\>(i,j) is non-zero.
const
GpuMat
&
mask
=
GpuMat
(),
Stream
&
stream
=
Stream
::
Null
());
*/
virtual
void
matchAsync
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
//! Download trainIdx, nMatches and distance and convert it to vector with DMatch.
OutputArray
matches
,
//! matches will be sorted in increasing order of distances.
InputArray
mask
=
noArray
(),
//! compactResult is used when mask is not empty. If compactResult is false matches
Stream
&
stream
=
Stream
::
Null
())
=
0
;
//! vector will have the same size as queryDescriptors rows. If compactResult is true
//! matches vector will not contain matches for fully masked out query descriptors.
/** @overload
static
void
radiusMatchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
distance
,
const
GpuMat
&
nMatches
,
*/
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
virtual
void
matchAsync
(
InputArray
queryDescriptors
,
//! Convert trainIdx, nMatches and distance to vector with DMatch.
OutputArray
matches
,
static
void
radiusMatchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
distance
,
const
Mat
&
nMatches
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
Stream
&
stream
=
Stream
::
Null
())
=
0
;
//! Find best matches for each query descriptor which have distance less than maxDistance
/** @brief Converts matches array from internal representation to standard matches vector.
//! in increasing order of distances).
void
radiusMatch
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
The method is supposed to be used with DescriptorMatcher::matchAsync to get final result.
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
Call this method only after DescriptorMatcher::matchAsync is completed (ie. after synchronization).
const
GpuMat
&
mask
=
GpuMat
(),
bool
compactResult
=
false
);
@param gpu_matches Matches, returned from DescriptorMatcher::matchAsync.
//! Find best matches for each query descriptor which have distance less than maxDistance.
@param matches Vector of DMatch objects.
//! If trainIdx is empty, then trainIdx and distance will be created with size nQuery x max((nQuery / 100), 10),
*/
//! otherwize user can pass own allocated trainIdx and distance with size nQuery x nMaxMatches
virtual
void
matchConvert
(
InputArray
gpu_matches
,
//! Matches doesn't sorted.
std
::
vector
<
DMatch
>&
matches
)
=
0
;
void
radiusMatchCollection
(
const
GpuMat
&
query
,
GpuMat
&
trainIdx
,
GpuMat
&
imgIdx
,
GpuMat
&
distance
,
GpuMat
&
nMatches
,
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
Stream
&
stream
=
Stream
::
Null
());
//
// knn match
//! Download trainIdx, imgIdx, nMatches and distance and convert it to vector with DMatch.
//
//! matches will be sorted in increasing order of distances.
//! compactResult is used when mask is not empty. If compactResult is false matches
/** @brief Finds the k best matches for each descriptor from a query set (blocking version).
//! vector will have the same size as queryDescriptors rows. If compactResult is true
//! matches vector will not contain matches for fully masked out query descriptors.
@param queryDescriptors Query set of descriptors.
static
void
radiusMatchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
imgIdx
,
const
GpuMat
&
distance
,
const
GpuMat
&
nMatches
,
@param trainDescriptors Train set of descriptors. This set is not added to the train descriptors
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
collection stored in the class object.
//! Convert trainIdx, nMatches and distance to vector with DMatch.
@param matches Matches. Each matches[i] is k or less matches for the same query descriptor.
static
void
radiusMatchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
imgIdx
,
const
Mat
&
distance
,
const
Mat
&
nMatches
,
@param k Count of best matches found per each query descriptor or less if a query descriptor has
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
less than k possible matches in total.
@param mask Mask specifying permissible matches between an input query and train matrices of
//! Find best matches from train collection for each query descriptor which have distance less than
descriptors.
//! maxDistance (in increasing order of distances).
@param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is
void
radiusMatch
(
const
GpuMat
&
query
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
false, the matches vector has the same size as queryDescriptors rows. If compactResult is true,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
bool
compactResult
=
false
);
the matches vector does not contain matches for fully masked-out query descriptors.
int
norm
;
These extended variants of DescriptorMatcher::match methods find several best matches for each query
descriptor. The matches are returned in the distance increasing order. See DescriptorMatcher::match
private
:
for the details about query and train descriptors.
std
::
vector
<
GpuMat
>
trainDescCollection
;
*/
virtual
void
knnMatch
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
InputArray
mask
=
noArray
(),
bool
compactResult
=
false
)
=
0
;
/** @overload
*/
virtual
void
knnMatch
(
InputArray
queryDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
bool
compactResult
=
false
)
=
0
;
/** @brief Finds the k best matches for each descriptor from a query set (asynchronous version).
@param queryDescriptors Query set of descriptors.
@param trainDescriptors Train set of descriptors. This set is not added to the train descriptors
collection stored in the class object.
@param matches Matches array stored in GPU memory. Internal representation is not defined.
Use DescriptorMatcher::knnMatchConvert method to retrieve results in standard representation.
@param k Count of best matches found per each query descriptor or less if a query descriptor has
less than k possible matches in total.
@param mask Mask specifying permissible matches between an input query and train matrices of
descriptors.
@param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is
false, the matches vector has the same size as queryDescriptors rows. If compactResult is true,
the matches vector does not contain matches for fully masked-out query descriptors.
@param stream CUDA stream.
These extended variants of DescriptorMatcher::matchAsync methods find several best matches for each query
descriptor. The matches are returned in the distance increasing order. See DescriptorMatcher::matchAsync
for the details about query and train descriptors.
*/
virtual
void
knnMatchAsync
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
OutputArray
matches
,
int
k
,
InputArray
mask
=
noArray
(),
Stream
&
stream
=
Stream
::
Null
())
=
0
;
/** @overload
*/
virtual
void
knnMatchAsync
(
InputArray
queryDescriptors
,
OutputArray
matches
,
int
k
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
Stream
&
stream
=
Stream
::
Null
())
=
0
;
/** @brief Converts matches array from internal representation to standard matches vector.
The method is supposed to be used with DescriptorMatcher::knnMatchAsync to get final result.
Call this method only after DescriptorMatcher::knnMatchAsync is completed (ie. after synchronization).
@param gpu_matches Matches, returned from DescriptorMatcher::knnMatchAsync.
@param matches Vector of DMatch objects.
@param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is
false, the matches vector has the same size as queryDescriptors rows. If compactResult is true,
the matches vector does not contain matches for fully masked-out query descriptors.
*/
virtual
void
knnMatchConvert
(
InputArray
gpu_matches
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
)
=
0
;
//
// radius match
//
/** @brief For each query descriptor, finds the training descriptors not farther than the specified distance (blocking version).
@param queryDescriptors Query set of descriptors.
@param trainDescriptors Train set of descriptors. This set is not added to the train descriptors
collection stored in the class object.
@param matches Found matches.
@param maxDistance Threshold for the distance between matched descriptors. Distance means here
metric distance (e.g. Hamming distance), not the distance between coordinates (which is measured
in Pixels)!
@param mask Mask specifying permissible matches between an input query and train matrices of
descriptors.
@param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is
false, the matches vector has the same size as queryDescriptors rows. If compactResult is true,
the matches vector does not contain matches for fully masked-out query descriptors.
For each query descriptor, the methods find such training descriptors that the distance between the
query descriptor and the training descriptor is equal or smaller than maxDistance. Found matches are
returned in the distance increasing order.
*/
virtual
void
radiusMatch
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
InputArray
mask
=
noArray
(),
bool
compactResult
=
false
)
=
0
;
/** @overload
*/
virtual
void
radiusMatch
(
InputArray
queryDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
bool
compactResult
=
false
)
=
0
;
/** @brief For each query descriptor, finds the training descriptors not farther than the specified distance (asynchronous version).
@param queryDescriptors Query set of descriptors.
@param trainDescriptors Train set of descriptors. This set is not added to the train descriptors
collection stored in the class object.
@param matches Matches array stored in GPU memory. Internal representation is not defined.
Use DescriptorMatcher::radiusMatchConvert method to retrieve results in standard representation.
@param maxDistance Threshold for the distance between matched descriptors. Distance means here
metric distance (e.g. Hamming distance), not the distance between coordinates (which is measured
in Pixels)!
@param mask Mask specifying permissible matches between an input query and train matrices of
descriptors.
@param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is
false, the matches vector has the same size as queryDescriptors rows. If compactResult is true,
the matches vector does not contain matches for fully masked-out query descriptors.
@param stream CUDA stream.
For each query descriptor, the methods find such training descriptors that the distance between the
query descriptor and the training descriptor is equal or smaller than maxDistance. Found matches are
returned in the distance increasing order.
*/
virtual
void
radiusMatchAsync
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
OutputArray
matches
,
float
maxDistance
,
InputArray
mask
=
noArray
(),
Stream
&
stream
=
Stream
::
Null
())
=
0
;
/** @overload
*/
virtual
void
radiusMatchAsync
(
InputArray
queryDescriptors
,
OutputArray
matches
,
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
Stream
&
stream
=
Stream
::
Null
())
=
0
;
/** @brief Converts matches array from internal representation to standard matches vector.
The method is supposed to be used with DescriptorMatcher::radiusMatchAsync to get final result.
Call this method only after DescriptorMatcher::radiusMatchAsync is completed (ie. after synchronization).
@param gpu_matches Matches, returned from DescriptorMatcher::radiusMatchAsync.
@param matches Vector of DMatch objects.
@param compactResult Parameter used when the mask (or masks) is not empty. If compactResult is
false, the matches vector has the same size as queryDescriptors rows. If compactResult is true,
the matches vector does not contain matches for fully masked-out query descriptors.
*/
virtual
void
radiusMatchConvert
(
InputArray
gpu_matches
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
)
=
0
;
};
};
//
//
...
...
modules/cudafeatures2d/perf/perf_features2d.cpp
View file @
8a178da1
...
@@ -167,16 +167,16 @@ PERF_TEST_P(DescSize_Norm, BFMatch,
...
@@ -167,16 +167,16 @@ PERF_TEST_P(DescSize_Norm, BFMatch,
if
(
PERF_RUN_CUDA
())
if
(
PERF_RUN_CUDA
())
{
{
cv
::
cuda
::
BFMatcher_CUDA
d_m
atcher
(
normType
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
d_matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFM
atcher
(
normType
);
const
cv
::
cuda
::
GpuMat
d_query
(
query
);
const
cv
::
cuda
::
GpuMat
d_query
(
query
);
const
cv
::
cuda
::
GpuMat
d_train
(
train
);
const
cv
::
cuda
::
GpuMat
d_train
(
train
);
cv
::
cuda
::
GpuMat
d_
trainIdx
,
d_distance
;
cv
::
cuda
::
GpuMat
d_
matches
;
TEST_CYCLE
()
d_matcher
.
matchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
);
TEST_CYCLE
()
d_matcher
->
matchAsync
(
d_query
,
d_train
,
d_matches
);
std
::
vector
<
cv
::
DMatch
>
gpu_matches
;
std
::
vector
<
cv
::
DMatch
>
gpu_matches
;
d_matcher
.
matchDownload
(
d_trainIdx
,
d_distance
,
gpu_matches
);
d_matcher
->
matchConvert
(
d_matches
,
gpu_matches
);
SANITY_CHECK_MATCHES
(
gpu_matches
);
SANITY_CHECK_MATCHES
(
gpu_matches
);
}
}
...
@@ -226,16 +226,16 @@ PERF_TEST_P(DescSize_K_Norm, BFKnnMatch,
...
@@ -226,16 +226,16 @@ PERF_TEST_P(DescSize_K_Norm, BFKnnMatch,
if
(
PERF_RUN_CUDA
())
if
(
PERF_RUN_CUDA
())
{
{
cv
::
cuda
::
BFMatcher_CUDA
d_m
atcher
(
normType
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
d_matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFM
atcher
(
normType
);
const
cv
::
cuda
::
GpuMat
d_query
(
query
);
const
cv
::
cuda
::
GpuMat
d_query
(
query
);
const
cv
::
cuda
::
GpuMat
d_train
(
train
);
const
cv
::
cuda
::
GpuMat
d_train
(
train
);
cv
::
cuda
::
GpuMat
d_
trainIdx
,
d_distance
,
d_allDist
;
cv
::
cuda
::
GpuMat
d_
matches
;
TEST_CYCLE
()
d_matcher
.
knnMatchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
,
d_allDist
,
k
);
TEST_CYCLE
()
d_matcher
->
knnMatchAsync
(
d_query
,
d_train
,
d_matches
,
k
);
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matchesTbl
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matchesTbl
;
d_matcher
.
knnMatchDownload
(
d_trainIdx
,
d_distance
,
matchesTbl
);
d_matcher
->
knnMatchConvert
(
d_matches
,
matchesTbl
);
std
::
vector
<
cv
::
DMatch
>
gpu_matches
;
std
::
vector
<
cv
::
DMatch
>
gpu_matches
;
toOneRowMatches
(
matchesTbl
,
gpu_matches
);
toOneRowMatches
(
matchesTbl
,
gpu_matches
);
...
@@ -280,16 +280,16 @@ PERF_TEST_P(DescSize_Norm, BFRadiusMatch,
...
@@ -280,16 +280,16 @@ PERF_TEST_P(DescSize_Norm, BFRadiusMatch,
if
(
PERF_RUN_CUDA
())
if
(
PERF_RUN_CUDA
())
{
{
cv
::
cuda
::
BFMatcher_CUDA
d_m
atcher
(
normType
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
d_matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFM
atcher
(
normType
);
const
cv
::
cuda
::
GpuMat
d_query
(
query
);
const
cv
::
cuda
::
GpuMat
d_query
(
query
);
const
cv
::
cuda
::
GpuMat
d_train
(
train
);
const
cv
::
cuda
::
GpuMat
d_train
(
train
);
cv
::
cuda
::
GpuMat
d_
trainIdx
,
d_nMatches
,
d_distance
;
cv
::
cuda
::
GpuMat
d_
matches
;
TEST_CYCLE
()
d_matcher
.
radiusMatchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
,
d_nM
atches
,
maxDistance
);
TEST_CYCLE
()
d_matcher
->
radiusMatchAsync
(
d_query
,
d_train
,
d_m
atches
,
maxDistance
);
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matchesTbl
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matchesTbl
;
d_matcher
.
radiusMatchDownload
(
d_trainIdx
,
d_distance
,
d_nM
atches
,
matchesTbl
);
d_matcher
->
radiusMatchConvert
(
d_m
atches
,
matchesTbl
);
std
::
vector
<
cv
::
DMatch
>
gpu_matches
;
std
::
vector
<
cv
::
DMatch
>
gpu_matches
;
toOneRowMatches
(
matchesTbl
,
gpu_matches
);
toOneRowMatches
(
matchesTbl
,
gpu_matches
);
...
...
modules/cudafeatures2d/src/brute_force_matcher.cpp
View file @
8a178da1
...
@@ -47,37 +47,7 @@ using namespace cv::cuda;
...
@@ -47,37 +47,7 @@ using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
cv
::
cuda
::
BFMatcher_CUDA
::
BFMatcher_CUDA
(
int
)
{
throw_no_cuda
();
}
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
int
)
{
throw_no_cuda
();
return
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
add
(
const
std
::
vector
<
GpuMat
>&
)
{
throw_no_cuda
();
}
const
std
::
vector
<
GpuMat
>&
cv
::
cuda
::
BFMatcher_CUDA
::
getTrainDescriptors
()
const
{
throw_no_cuda
();
return
trainDescCollection
;
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
clear
()
{
throw_no_cuda
();
}
bool
cv
::
cuda
::
BFMatcher_CUDA
::
empty
()
const
{
throw_no_cuda
();
return
true
;
}
bool
cv
::
cuda
::
BFMatcher_CUDA
::
isMaskSupported
()
const
{
throw_no_cuda
();
return
true
;
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchSingle
(
const
GpuMat
&
,
const
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
const
GpuMat
&
,
Stream
&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchDownload
(
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
DMatch
>&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchConvert
(
const
Mat
&
,
const
Mat
&
,
std
::
vector
<
DMatch
>&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
match
(
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
DMatch
>&
,
const
GpuMat
&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
makeGpuCollection
(
GpuMat
&
,
GpuMat
&
,
const
std
::
vector
<
GpuMat
>&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchCollection
(
const
GpuMat
&
,
const
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
const
GpuMat
&
,
Stream
&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchDownload
(
const
GpuMat
&
,
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
DMatch
>&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchConvert
(
const
Mat
&
,
const
Mat
&
,
const
Mat
&
,
std
::
vector
<
DMatch
>&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
match
(
const
GpuMat
&
,
std
::
vector
<
DMatch
>&
,
const
std
::
vector
<
GpuMat
>&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatchSingle
(
const
GpuMat
&
,
const
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
int
,
const
GpuMat
&
,
Stream
&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatchDownload
(
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatchConvert
(
const
Mat
&
,
const
Mat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch
(
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
int
,
const
GpuMat
&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch2Collection
(
const
GpuMat
&
,
const
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
const
GpuMat
&
,
Stream
&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch2Download
(
const
GpuMat
&
,
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch2Convert
(
const
Mat
&
,
const
Mat
&
,
const
Mat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch
(
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
int
,
const
std
::
vector
<
GpuMat
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchSingle
(
const
GpuMat
&
,
const
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
float
,
const
GpuMat
&
,
Stream
&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchDownload
(
const
GpuMat
&
,
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchConvert
(
const
Mat
&
,
const
Mat
&
,
const
Mat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatch
(
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
float
,
const
GpuMat
&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchCollection
(
const
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
GpuMat
&
,
float
,
const
std
::
vector
<
GpuMat
>&
,
Stream
&
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchDownload
(
const
GpuMat
&
,
const
GpuMat
&
,
const
GpuMat
&
,
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchConvert
(
const
Mat
&
,
const
Mat
&
,
const
Mat
&
,
const
Mat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
bool
)
{
throw_no_cuda
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatch
(
const
GpuMat
&
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
,
float
,
const
std
::
vector
<
GpuMat
>&
,
bool
)
{
throw_no_cuda
();
}
#else
/* !defined (HAVE_CUDA) */
#else
/* !defined (HAVE_CUDA) */
...
@@ -155,857 +125,953 @@ namespace cv { namespace cuda { namespace device
...
@@ -155,857 +125,953 @@ namespace cv { namespace cuda { namespace device
}
}
}}}
}}}
////////////////////////////////////////////////////////////////////
namespace
// Train collection
cv
::
cuda
::
BFMatcher_CUDA
::
BFMatcher_CUDA
(
int
norm_
)
:
norm
(
norm_
)
{
{
}
static
void
makeGpuCollection
(
const
std
::
vector
<
GpuMat
>&
trainDescCollection
,
const
std
::
vector
<
GpuMat
>&
masks
,
GpuMat
&
trainCollection
,
GpuMat
&
maskCollection
)
{
if
(
trainDescCollection
.
empty
())
return
;
void
cv
::
cuda
::
BFMatcher_CUDA
::
add
(
const
std
::
vector
<
GpuMat
>&
descCollection
)
if
(
masks
.
empty
())
{
{
trainDescCollection
.
insert
(
trainDescCollection
.
end
(),
descCollection
.
begin
(),
descCollection
.
end
());
Mat
trainCollectionCPU
(
1
,
static_cast
<
int
>
(
trainDescCollection
.
size
()),
CV_8UC
(
sizeof
(
PtrStepSzb
)));
}
const
std
::
vector
<
GpuMat
>&
cv
::
cuda
::
BFMatcher_CUDA
::
getTrainDescriptors
()
const
PtrStepSzb
*
trainCollectionCPU_ptr
=
trainCollectionCPU
.
ptr
<
PtrStepSzb
>
();
{
return
trainDescCollection
;
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
clear
()
for
(
size_t
i
=
0
,
size
=
trainDescCollection
.
size
();
i
<
size
;
++
i
,
++
trainCollectionCPU_ptr
)
{
*
trainCollectionCPU_ptr
=
trainDescCollection
[
i
];
trainDescCollection
.
clear
();
}
bool
cv
::
cuda
::
BFMatcher_CUDA
::
empty
()
const
trainCollection
.
upload
(
trainCollectionCPU
);
{
maskCollection
.
release
();
return
trainDescCollection
.
empty
();
}
}
else
{
CV_Assert
(
masks
.
size
()
==
trainDescCollection
.
size
()
);
bool
cv
::
cuda
::
BFMatcher_CUDA
::
isMaskSupported
()
const
Mat
trainCollectionCPU
(
1
,
static_cast
<
int
>
(
trainDescCollection
.
size
()),
CV_8UC
(
sizeof
(
PtrStepSzb
)));
{
Mat
maskCollectionCPU
(
1
,
static_cast
<
int
>
(
trainDescCollection
.
size
()),
CV_8UC
(
sizeof
(
PtrStepb
)));
return
true
;
}
////////////////////////////////////////////////////////////////////
PtrStepSzb
*
trainCollectionCPU_ptr
=
trainCollectionCPU
.
ptr
<
PtrStepSzb
>
();
// Match
PtrStepb
*
maskCollectionCPU_ptr
=
maskCollectionCPU
.
ptr
<
PtrStepb
>
();
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchSingle
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
for
(
size_t
i
=
0
,
size
=
trainDescCollection
.
size
();
i
<
size
;
++
i
,
++
trainCollectionCPU_ptr
,
++
maskCollectionCPU_ptr
)
GpuMat
&
trainIdx
,
GpuMat
&
distance
,
{
const
GpuMat
&
mask
,
Stream
&
stream
)
const
GpuMat
&
train
=
trainDescCollection
[
i
];
{
const
GpuMat
&
mask
=
masks
[
i
];
if
(
query
.
empty
()
||
train
.
empty
())
return
;
using
namespace
cv
::
cuda
::
device
::
bf_match
;
CV_Assert
(
mask
.
empty
()
||
(
mask
.
type
()
==
CV_8UC1
&&
mask
.
cols
==
train
.
rows
)
)
;
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
train
,
const
PtrStepSzb
&
mask
,
*
trainCollectionCPU_ptr
=
train
;
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzf
&
distance
,
*
maskCollectionCPU_ptr
=
mask
;
cudaStream_t
stream
);
}
static
const
caller_t
callersL1
[]
=
trainCollection
.
upload
(
trainCollectionCPU
);
{
maskCollection
.
upload
(
maskCollectionCPU
);
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
}
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
}
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
class
BFMatcher_Impl
:
public
cv
::
cuda
::
DescriptorMatcher
{
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
public
:
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
explicit
BFMatcher_Impl
(
int
norm
)
:
norm_
(
norm
)
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
{
};
CV_Assert
(
norm
==
NORM_L1
||
norm
==
NORM_L2
||
norm
==
NORM_HAMMING
);
}
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
CV_Assert
(
train
.
cols
==
query
.
cols
&&
train
.
type
()
==
query
.
type
());
CV_Assert
(
norm
==
NORM_L1
||
norm
==
NORM_L2
||
norm
==
NORM_HAMMING
);
const
caller_t
*
callers
=
norm
==
NORM_L1
?
callersL1
:
norm
==
NORM_L2
?
callersL2
:
callersHamming
;
const
int
nQuery
=
query
.
rows
;
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32S
,
trainIdx
);
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32F
,
distance
);
caller_t
func
=
callers
[
query
.
depth
()];
CV_Assert
(
func
!=
0
);
func
(
query
,
train
,
mask
,
trainIdx
,
distance
,
StreamAccessor
::
getStream
(
stream
));
virtual
bool
isMaskSupported
()
const
{
return
true
;
}
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
distance
,
std
::
vector
<
DMatch
>&
matche
s
)
virtual
void
add
(
const
std
::
vector
<
GpuMat
>&
descriptor
s
)
{
{
if
(
trainIdx
.
empty
()
||
distance
.
empty
())
trainDescCollection_
.
insert
(
trainDescCollection_
.
end
(),
descriptors
.
begin
(),
descriptors
.
end
());
return
;
}
Mat
trainIdxCPU
(
trainIdx
);
virtual
const
std
::
vector
<
GpuMat
>&
getTrainDescriptors
()
const
Mat
distanceCPU
(
distance
);
{
return
trainDescCollection_
;
}
matchConvert
(
trainIdxCPU
,
distanceCPU
,
matches
);
virtual
void
clear
()
}
{
trainDescCollection_
.
clear
();
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
distance
,
std
::
vector
<
DMatch
>&
matches
)
virtual
bool
empty
()
const
{
{
if
(
trainIdx
.
empty
()
||
distance
.
empty
())
return
trainDescCollection_
.
empty
();
return
;
}
CV_Assert
(
trainIdx
.
type
()
==
CV_32SC1
);
virtual
void
train
()
CV_Assert
(
distance
.
type
()
==
CV_32FC1
&&
distance
.
cols
==
trainIdx
.
cols
);
{
}
const
int
nQuery
=
trainIdx
.
cols
;
virtual
void
match
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
std
::
vector
<
DMatch
>&
matches
,
InputArray
mask
=
noArray
());
virtual
void
match
(
InputArray
queryDescriptors
,
std
::
vector
<
DMatch
>&
matches
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
());
virtual
void
matchAsync
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
OutputArray
matches
,
InputArray
mask
=
noArray
(),
Stream
&
stream
=
Stream
::
Null
());
virtual
void
matchAsync
(
InputArray
queryDescriptors
,
OutputArray
matches
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
Stream
&
stream
=
Stream
::
Null
());
virtual
void
matchConvert
(
InputArray
gpu_matches
,
std
::
vector
<
DMatch
>&
matches
);
virtual
void
knnMatch
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
InputArray
mask
=
noArray
(),
bool
compactResult
=
false
);
virtual
void
knnMatch
(
InputArray
queryDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
bool
compactResult
=
false
);
virtual
void
knnMatchAsync
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
OutputArray
matches
,
int
k
,
InputArray
mask
=
noArray
(),
Stream
&
stream
=
Stream
::
Null
());
virtual
void
knnMatchAsync
(
InputArray
queryDescriptors
,
OutputArray
matches
,
int
k
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
Stream
&
stream
=
Stream
::
Null
());
virtual
void
knnMatchConvert
(
InputArray
gpu_matches
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
virtual
void
radiusMatch
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
InputArray
mask
=
noArray
(),
bool
compactResult
=
false
);
virtual
void
radiusMatch
(
InputArray
queryDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
bool
compactResult
=
false
);
virtual
void
radiusMatchAsync
(
InputArray
queryDescriptors
,
InputArray
trainDescriptors
,
OutputArray
matches
,
float
maxDistance
,
InputArray
mask
=
noArray
(),
Stream
&
stream
=
Stream
::
Null
());
virtual
void
radiusMatchAsync
(
InputArray
queryDescriptors
,
OutputArray
matches
,
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
=
std
::
vector
<
GpuMat
>
(),
Stream
&
stream
=
Stream
::
Null
());
virtual
void
radiusMatchConvert
(
InputArray
gpu_matches
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
=
false
);
private
:
int
norm_
;
std
::
vector
<
GpuMat
>
trainDescCollection_
;
};
matches
.
clear
();
//
matches
.
reserve
(
nQuery
);
// 1 to 1 match
//
const
int
*
trainIdx_ptr
=
trainIdx
.
ptr
<
int
>
();
void
BFMatcher_Impl
::
match
(
InputArray
_queryDescriptors
,
InputArray
_trainDescriptors
,
const
float
*
distance_ptr
=
distance
.
ptr
<
float
>
();
std
::
vector
<
DMatch
>&
matches
,
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
,
++
trainIdx_ptr
,
++
distance_ptr
)
InputArray
_mask
)
{
{
int
train_idx
=
*
trainIdx_ptr
;
GpuMat
d_matches
;
matchAsync
(
_queryDescriptors
,
_trainDescriptors
,
d_matches
,
_mask
);
if
(
train_idx
==
-
1
)
matchConvert
(
d_matches
,
matches
);
continue
;
float
distance_local
=
*
distance_ptr
;
DMatch
m
(
queryIdx
,
train_idx
,
0
,
distance_local
);
matches
.
push_back
(
m
);
}
}
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
match
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
std
::
vector
<
DMatch
>&
matches
,
const
GpuMat
&
mask
)
{
GpuMat
trainIdx
,
distance
;
matchSingle
(
query
,
train
,
trainIdx
,
distance
,
mask
);
matchDownload
(
trainIdx
,
distance
,
matches
);
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
makeGpuCollection
(
GpuMat
&
trainCollection
,
GpuMat
&
maskCollection
,
const
std
::
vector
<
GpuMat
>&
masks
)
{
if
(
empty
())
return
;
if
(
masks
.
empty
())
void
BFMatcher_Impl
::
match
(
InputArray
_queryDescriptors
,
std
::
vector
<
DMatch
>&
matches
,
const
std
::
vector
<
GpuMat
>&
masks
)
{
{
Mat
trainCollectionCPU
(
1
,
static_cast
<
int
>
(
trainDescCollection
.
size
()),
CV_8UC
(
sizeof
(
PtrStepSzb
)));
GpuMat
d_matches
;
matchAsync
(
_queryDescriptors
,
d_matches
,
masks
);
matchConvert
(
d_matches
,
matches
);
}
PtrStepSzb
*
trainCollectionCPU_ptr
=
trainCollectionCPU
.
ptr
<
PtrStepSzb
>
();
void
BFMatcher_Impl
::
matchAsync
(
InputArray
_queryDescriptors
,
InputArray
_trainDescriptors
,
OutputArray
_matches
,
InputArray
_mask
,
Stream
&
stream
)
{
using
namespace
cv
::
cuda
::
device
::
bf_match
;
for
(
size_t
i
=
0
,
size
=
trainDescCollection
.
size
();
i
<
size
;
++
i
,
++
trainCollectionCPU_ptr
)
const
GpuMat
query
=
_queryDescriptors
.
getGpuMat
();
*
trainCollectionCPU_ptr
=
trainDescCollection
[
i
];
const
GpuMat
train
=
_trainDescriptors
.
getGpuMat
();
const
GpuMat
mask
=
_mask
.
getGpuMat
();
trainCollection
.
upload
(
trainCollectionCPU
);
if
(
query
.
empty
()
||
train
.
empty
())
maskCollection
.
release
();
{
}
_matches
.
release
();
else
return
;
{
}
CV_Assert
(
masks
.
size
()
==
trainDescCollection
.
size
());
Mat
trainCollectionCPU
(
1
,
static_cast
<
int
>
(
trainDescCollection
.
size
()),
CV_8UC
(
sizeof
(
PtrStepSzb
)));
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
Mat
maskCollectionCPU
(
1
,
static_cast
<
int
>
(
trainDescCollection
.
size
()),
CV_8UC
(
sizeof
(
PtrStepb
)));
CV_Assert
(
train
.
cols
==
query
.
cols
&&
train
.
type
()
==
query
.
type
()
);
CV_Assert
(
mask
.
empty
()
||
(
mask
.
type
()
==
CV_8UC1
&&
mask
.
rows
==
query
.
rows
&&
mask
.
cols
==
train
.
rows
)
);
PtrStepSzb
*
trainCollectionCPU_ptr
=
trainCollectionCPU
.
ptr
<
PtrStepSzb
>
();
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
train
,
const
PtrStepSzb
&
mask
,
PtrStepb
*
maskCollectionCPU_ptr
=
maskCollectionCPU
.
ptr
<
PtrStepb
>
();
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzf
&
distance
,
cudaStream_t
stream
);
for
(
size_t
i
=
0
,
size
=
trainDescCollection
.
size
();
i
<
size
;
++
i
,
++
trainCollectionCPU_ptr
,
++
maskCollectionCPU_ptr
)
static
const
caller_t
callersL1
[]
=
{
{
const
GpuMat
&
train
=
trainDescCollection
[
i
];
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
const
GpuMat
&
mask
=
masks
[
i
];
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
CV_Assert
(
mask
.
empty
()
||
(
mask
.
type
()
==
CV_8UC1
&&
mask
.
cols
==
train
.
rows
))
;
const
caller_t
*
callers
=
norm_
==
NORM_L1
?
callersL1
:
norm_
==
NORM_L2
?
callersL2
:
callersHamming
;
*
trainCollectionCPU_ptr
=
train
;
const
caller_t
func
=
callers
[
query
.
depth
()];
*
maskCollectionCPU_ptr
=
mask
;
if
(
func
==
0
)
{
CV_Error
(
Error
::
StsUnsupportedFormat
,
"unsupported combination of query.depth() and norm"
);
}
}
trainCollection
.
upload
(
trainCollectionCPU
);
const
int
nQuery
=
query
.
rows
;
maskCollection
.
upload
(
maskCollectionCPU
);
}
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchCollection
(
const
GpuMat
&
query
,
const
GpuMat
&
trainCollection
,
_matches
.
create
(
2
,
nQuery
,
CV_32SC1
);
GpuMat
&
trainIdx
,
GpuMat
&
imgIdx
,
GpuMat
&
distance
,
GpuMat
matches
=
_matches
.
getGpuMat
();
const
GpuMat
&
masks
,
Stream
&
stream
)
{
if
(
query
.
empty
()
||
trainCollection
.
empty
())
return
;
using
namespace
cv
::
cuda
::
device
::
bf_match
;
GpuMat
trainIdx
(
1
,
nQuery
,
CV_32SC1
,
matches
.
ptr
(
0
));
GpuMat
distance
(
1
,
nQuery
,
CV_32FC1
,
matches
.
ptr
(
1
));
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
trains
,
const
PtrStepSz
<
PtrStepb
>&
masks
,
func
(
query
,
train
,
mask
,
trainIdx
,
distance
,
StreamAccessor
::
getStream
(
stream
));
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzi
&
imgIdx
,
const
PtrStepSzf
&
distance
,
}
cudaStream_t
stream
);
static
const
caller_t
callersL1
[]
=
void
BFMatcher_Impl
::
matchAsync
(
InputArray
_queryDescriptors
,
{
OutputArray
_matches
,
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
const
std
::
vector
<
GpuMat
>&
masks
,
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
Stream
&
stream
)
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
using
namespace
cv
::
cuda
::
device
::
bf_match
;
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
const
GpuMat
query
=
_queryDescriptors
.
getGpuMat
();
CV_Assert
(
norm
==
NORM_L1
||
norm
==
NORM_L2
||
norm
==
NORM_HAMMING
);
const
caller_t
*
callers
=
norm
==
NORM_L1
?
callersL1
:
norm
==
NORM_L2
?
callersL2
:
callersHamming
;
if
(
query
.
empty
()
||
trainDescCollection_
.
empty
())
{
const
int
nQuery
=
query
.
rows
;
_matches
.
release
();
return
;
}
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32S
,
trainIdx
);
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32S
,
imgIdx
);
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32F
,
distance
);
caller_t
func
=
callers
[
query
.
depth
()]
;
GpuMat
trainCollection
,
maskCollection
;
CV_Assert
(
func
!=
0
);
makeGpuCollection
(
trainDescCollection_
,
masks
,
trainCollection
,
maskCollection
);
func
(
query
,
trainCollection
,
masks
,
trainIdx
,
imgIdx
,
distance
,
StreamAccessor
::
getStream
(
stream
));
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
trains
,
const
PtrStepSz
<
PtrStepb
>&
masks
,
}
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzi
&
imgIdx
,
const
PtrStepSzf
&
distance
,
cudaStream_t
stream
);
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
imgIdx
,
const
GpuMat
&
distance
,
std
::
vector
<
DMatch
>&
matches
)
static
const
caller_t
callersL1
[]
=
{
{
if
(
trainIdx
.
empty
()
||
imgIdx
.
empty
()
||
distance
.
empty
())
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
return
;
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
Mat
trainIdxCPU
(
trainIdx
);
const
caller_t
*
callers
=
norm_
==
NORM_L1
?
callersL1
:
norm_
==
NORM_L2
?
callersL2
:
callersHamming
;
Mat
imgIdxCPU
(
imgIdx
);
Mat
distanceCPU
(
distance
);
matchConvert
(
trainIdxCPU
,
imgIdxCPU
,
distanceCPU
,
matches
);
const
caller_t
func
=
callers
[
query
.
depth
()];
}
if
(
func
==
0
)
{
CV_Error
(
Error
::
StsUnsupportedFormat
,
"unsupported combination of query.depth() and norm"
);
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
matchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
imgIdx
,
const
Mat
&
distance
,
std
::
vector
<
DMatch
>&
matches
)
const
int
nQuery
=
query
.
rows
;
{
if
(
trainIdx
.
empty
()
||
imgIdx
.
empty
()
||
distance
.
empty
())
return
;
CV_Assert
(
trainIdx
.
type
()
==
CV_32SC1
);
_matches
.
create
(
3
,
nQuery
,
CV_32SC1
);
CV_Assert
(
imgIdx
.
type
()
==
CV_32SC1
&&
imgIdx
.
cols
==
trainIdx
.
cols
);
GpuMat
matches
=
_matches
.
getGpuMat
();
CV_Assert
(
distance
.
type
()
==
CV_32FC1
&&
distance
.
cols
==
trainIdx
.
cols
);
const
int
nQuery
=
trainIdx
.
cols
;
GpuMat
trainIdx
(
1
,
nQuery
,
CV_32SC1
,
matches
.
ptr
(
0
));
GpuMat
imgIdx
(
1
,
nQuery
,
CV_32SC1
,
matches
.
ptr
(
1
));
GpuMat
distance
(
1
,
nQuery
,
CV_32FC1
,
matches
.
ptr
(
2
));
matches
.
clear
(
);
func
(
query
,
trainCollection
,
maskCollection
,
trainIdx
,
imgIdx
,
distance
,
StreamAccessor
::
getStream
(
stream
)
);
matches
.
reserve
(
nQuery
);
}
const
int
*
trainIdx_ptr
=
trainIdx
.
ptr
<
int
>
();
void
BFMatcher_Impl
::
matchConvert
(
InputArray
_gpu_matches
,
const
int
*
imgIdx_ptr
=
imgIdx
.
ptr
<
int
>
();
std
::
vector
<
DMatch
>&
matches
)
const
float
*
distance_ptr
=
distance
.
ptr
<
float
>
();
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
,
++
trainIdx_ptr
,
++
imgIdx_ptr
,
++
distance_ptr
)
{
{
int
_trainIdx
=
*
trainIdx_ptr
;
Mat
gpu_matches
;
if
(
_gpu_matches
.
kind
()
==
_InputArray
::
CUDA_GPU_MAT
)
if
(
_trainIdx
==
-
1
)
{
continue
;
_gpu_matches
.
getGpuMat
().
download
(
gpu_matches
);
}
int
_imgIdx
=
*
imgIdx_ptr
;
else
{
gpu_matches
=
_gpu_matches
.
getMat
();
}
float
_distance
=
*
distance_ptr
;
if
(
gpu_matches
.
empty
())
{
matches
.
clear
();
return
;
}
DMatch
m
(
queryIdx
,
_trainIdx
,
_imgIdx
,
_distance
);
CV_Assert
(
(
gpu_matches
.
type
()
==
CV_32SC1
)
&&
(
gpu_matches
.
rows
==
2
||
gpu_matches
.
rows
==
3
)
);
matches
.
push_back
(
m
);
const
int
nQuery
=
gpu_matches
.
cols
;
}
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
match
(
const
GpuMat
&
query
,
std
::
vector
<
DMatch
>&
matches
,
const
std
::
vector
<
GpuMat
>&
masks
)
matches
.
clear
();
{
matches
.
reserve
(
nQuery
);
GpuMat
trainCollection
;
GpuMat
maskCollection
;
makeGpuCollection
(
trainCollection
,
maskCollection
,
masks
);
const
int
*
trainIdxPtr
=
NULL
;
const
int
*
imgIdxPtr
=
NULL
;
const
float
*
distancePtr
=
NULL
;
GpuMat
trainIdx
,
imgIdx
,
distance
;
if
(
gpu_matches
.
rows
==
2
)
{
trainIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
0
);
distancePtr
=
gpu_matches
.
ptr
<
float
>
(
1
);
}
else
{
trainIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
0
);
imgIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
1
);
distancePtr
=
gpu_matches
.
ptr
<
float
>
(
2
);
}
matchCollection
(
query
,
trainCollection
,
trainIdx
,
imgIdx
,
distance
,
maskCollection
);
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
)
matchDownload
(
trainIdx
,
imgIdx
,
distance
,
matches
);
{
}
const
int
trainIdx
=
trainIdxPtr
[
queryIdx
];
if
(
trainIdx
==
-
1
)
continue
;
////////////////////////////////////////////////////////////////////
const
int
imgIdx
=
imgIdxPtr
?
imgIdxPtr
[
queryIdx
]
:
0
;
// KnnMatch
const
float
distance
=
distancePtr
[
queryIdx
];
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatchSingle
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
DMatch
m
(
queryIdx
,
trainIdx
,
imgIdx
,
distance
);
GpuMat
&
trainIdx
,
GpuMat
&
distance
,
GpuMat
&
allDist
,
int
k
,
const
GpuMat
&
mask
,
Stream
&
stream
)
{
if
(
query
.
empty
()
||
train
.
empty
())
return
;
using
namespace
cv
::
cuda
::
device
::
bf_knnmatch
;
matches
.
push_back
(
m
);
}
}
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
train
,
int
k
,
const
PtrStepSzb
&
mask
,
//
const
PtrStepSzb
&
trainIdx
,
const
PtrStepSzb
&
distance
,
const
PtrStepSzf
&
allDist
,
// knn match
cudaStream_t
stream
);
//
static
const
caller_t
callersL1
[]
=
void
BFMatcher_Impl
::
knnMatch
(
InputArray
_queryDescriptors
,
InputArray
_trainDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
InputArray
_mask
,
bool
compactResult
)
{
{
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
GpuMat
d_matches
;
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
knnMatchAsync
(
_queryDescriptors
,
_trainDescriptors
,
d_matches
,
k
,
_mask
);
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
knnMatchConvert
(
d_matches
,
matches
,
compactResult
);
};
}
static
const
caller_t
callersL2
[]
=
{
void
BFMatcher_Impl
::
knnMatch
(
InputArray
_queryDescriptors
,
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
int
k
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
const
std
::
vector
<
GpuMat
>&
masks
,
};
bool
compactResult
)
static
const
caller_t
callersHamming
[]
=
{
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
if
(
k
==
2
)
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
{
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
GpuMat
d_matches
;
};
knnMatchAsync
(
_queryDescriptors
,
d_matches
,
k
,
masks
);
knnMatchConvert
(
d_matches
,
matches
,
compactResult
);
}
else
{
const
GpuMat
query
=
_queryDescriptors
.
getGpuMat
();
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
if
(
query
.
empty
()
||
trainDescCollection_
.
empty
())
CV_Assert
(
train
.
type
()
==
query
.
type
()
&&
train
.
cols
==
query
.
cols
);
{
CV_Assert
(
norm
==
NORM_L1
||
norm
==
NORM_L2
||
norm
==
NORM_HAMMING
);
matches
.
clear
();
return
;
}
const
caller_t
*
callers
=
norm
==
NORM_L1
?
callersL1
:
norm
==
NORM_L2
?
callersL2
:
callersHamming
;
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
)
;
const
int
nQuery
=
query
.
rows
;
std
::
vector
<
std
::
vector
<
DMatch
>
>
curMatches
;
const
int
nTrain
=
train
.
rows
;
std
::
vector
<
DMatch
>
temp
;
temp
.
reserve
(
2
*
k
);
if
(
k
==
2
)
matches
.
resize
(
query
.
rows
);
{
for
(
size_t
i
=
0
;
i
<
matches
.
size
();
++
i
)
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32SC2
,
trainIdx
);
matches
[
i
].
reserve
(
k
);
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32FC2
,
distance
);
}
else
{
ensureSizeIsEnough
(
nQuery
,
k
,
CV_32S
,
trainIdx
);
ensureSizeIsEnough
(
nQuery
,
k
,
CV_32F
,
distance
);
ensureSizeIsEnough
(
nQuery
,
nTrain
,
CV_32FC1
,
allDist
);
}
trainIdx
.
setTo
(
Scalar
::
all
(
-
1
),
stream
);
for
(
size_t
imgIdx
=
0
;
imgIdx
<
trainDescCollection_
.
size
();
++
imgIdx
)
{
knnMatch
(
query
,
trainDescCollection_
[
imgIdx
],
curMatches
,
k
,
masks
.
empty
()
?
GpuMat
()
:
masks
[
imgIdx
]);
caller_t
func
=
callers
[
query
.
depth
()];
for
(
int
queryIdx
=
0
;
queryIdx
<
query
.
rows
;
++
queryIdx
)
CV_Assert
(
func
!=
0
);
{
std
::
vector
<
DMatch
>&
localMatch
=
curMatches
[
queryIdx
];
std
::
vector
<
DMatch
>&
globalMatch
=
matches
[
queryIdx
];
func
(
query
,
train
,
k
,
mask
,
trainIdx
,
distance
,
allDist
,
StreamAccessor
::
getStream
(
stream
));
for
(
size_t
i
=
0
;
i
<
localMatch
.
size
();
++
i
)
}
localMatch
[
i
].
imgIdx
=
imgIdx
;
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
distance
,
temp
.
clear
();
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
std
::
merge
(
globalMatch
.
begin
(),
globalMatch
.
end
(),
localMatch
.
begin
(),
localMatch
.
end
(),
std
::
back_inserter
(
temp
));
{
if
(
trainIdx
.
empty
()
||
distance
.
empty
())
return
;
Mat
trainIdxCPU
(
trainIdx
);
globalMatch
.
clear
();
Mat
distanceCPU
(
distance
);
const
size_t
count
=
std
::
min
(
static_cast
<
size_t
>
(
k
),
temp
.
size
());
std
::
copy
(
temp
.
begin
(),
temp
.
begin
()
+
count
,
std
::
back_inserter
(
globalMatch
));
}
}
knnMatchConvert
(
trainIdxCPU
,
distanceCPU
,
matches
,
compactResult
);
if
(
compactResult
)
}
{
std
::
vector
<
std
::
vector
<
DMatch
>
>::
iterator
new_end
=
std
::
remove_if
(
matches
.
begin
(),
matches
.
end
(),
std
::
mem_fun_ref
(
&
std
::
vector
<
DMatch
>::
empty
));
matches
.
erase
(
new_end
,
matches
.
end
());
}
}
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
distance
,
void
BFMatcher_Impl
::
knnMatchAsync
(
InputArray
_queryDescriptors
,
InputArray
_trainDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
OutputArray
_matches
,
{
int
k
,
if
(
trainIdx
.
empty
()
||
distance
.
empty
())
InputArray
_mask
,
return
;
Stream
&
stream
)
{
using
namespace
cv
::
cuda
::
device
::
bf_knnmatch
;
CV_Assert
(
trainIdx
.
type
()
==
CV_32SC2
||
trainIdx
.
type
()
==
CV_32SC1
);
const
GpuMat
query
=
_queryDescriptors
.
getGpuMat
();
CV_Assert
(
distance
.
type
()
==
CV_32FC2
||
distance
.
type
()
==
CV_32FC1
);
const
GpuMat
train
=
_trainDescriptors
.
getGpuMat
();
CV_Assert
(
distance
.
size
()
==
trainIdx
.
size
());
const
GpuMat
mask
=
_mask
.
getGpuMat
();
CV_Assert
(
trainIdx
.
isContinuous
()
&&
distance
.
isContinuous
());
if
(
query
.
empty
()
||
train
.
empty
())
{
_matches
.
release
();
return
;
}
const
int
nQuery
=
trainIdx
.
type
()
==
CV_32SC2
?
trainIdx
.
cols
:
trainIdx
.
rows
;
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
const
int
k
=
trainIdx
.
type
()
==
CV_32SC2
?
2
:
trainIdx
.
cols
;
CV_Assert
(
train
.
cols
==
query
.
cols
&&
train
.
type
()
==
query
.
type
()
);
CV_Assert
(
mask
.
empty
()
||
(
mask
.
type
()
==
CV_8UC1
&&
mask
.
rows
==
query
.
rows
&&
mask
.
cols
==
train
.
rows
)
);
matches
.
clear
();
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
train
,
int
k
,
const
PtrStepSzb
&
mask
,
matches
.
reserve
(
nQuery
);
const
PtrStepSzb
&
trainIdx
,
const
PtrStepSzb
&
distance
,
const
PtrStepSzf
&
allDist
,
cudaStream_t
stream
);
const
int
*
trainIdx_ptr
=
trainIdx
.
ptr
<
int
>
();
static
const
caller_t
callersL1
[]
=
const
float
*
distance_ptr
=
distance
.
ptr
<
float
>
();
{
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
)
const
caller_t
*
callers
=
norm_
==
NORM_L1
?
callersL1
:
norm_
==
NORM_L2
?
callersL2
:
callersHamming
;
{
matches
.
push_back
(
std
::
vector
<
DMatch
>
());
std
::
vector
<
DMatch
>&
curMatches
=
matches
.
back
();
curMatches
.
reserve
(
k
);
for
(
int
i
=
0
;
i
<
k
;
++
i
,
++
trainIdx_ptr
,
++
distance_ptr
)
const
caller_t
func
=
callers
[
query
.
depth
()];
if
(
func
==
0
)
{
{
int
_trainIdx
=
*
trainIdx_ptr
;
CV_Error
(
Error
::
StsUnsupportedFormat
,
"unsupported combination of query.depth() and norm"
);
}
if
(
_trainIdx
!=
-
1
)
const
int
nQuery
=
query
.
rows
;
{
const
int
nTrain
=
train
.
rows
;
float
_distance
=
*
distance_ptr
;
DMatch
m
(
queryIdx
,
_trainIdx
,
0
,
_distance
);
GpuMat
trainIdx
,
distance
,
allDist
;
if
(
k
==
2
)
{
_matches
.
create
(
2
,
nQuery
,
CV_32SC2
);
GpuMat
matches
=
_matches
.
getGpuMat
();
curMatches
.
push_back
(
m
);
trainIdx
=
GpuMat
(
1
,
nQuery
,
CV_32SC2
,
matches
.
ptr
(
0
)
);
}
distance
=
GpuMat
(
1
,
nQuery
,
CV_32FC2
,
matches
.
ptr
(
1
));
}
}
else
{
_matches
.
create
(
2
*
nQuery
,
k
,
CV_32SC1
);
GpuMat
matches
=
_matches
.
getGpuMat
();
if
(
compactResult
&&
curMatches
.
empty
())
trainIdx
=
GpuMat
(
nQuery
,
k
,
CV_32SC1
,
matches
.
ptr
(
0
),
matches
.
step
);
matches
.
pop_back
();
distance
=
GpuMat
(
nQuery
,
k
,
CV_32FC1
,
matches
.
ptr
(
nQuery
),
matches
.
step
);
}
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
const
GpuMat
&
mask
,
bool
compactResult
)
{
GpuMat
trainIdx
,
distance
,
allDist
;
knnMatchSingle
(
query
,
train
,
trainIdx
,
distance
,
allDist
,
k
,
mask
);
knnMatchDownload
(
trainIdx
,
distance
,
matches
,
compactResult
);
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch2Collection
(
const
GpuMat
&
query
,
const
GpuMat
&
trainCollection
,
BufferPool
pool
(
stream
);
GpuMat
&
trainIdx
,
GpuMat
&
imgIdx
,
GpuMat
&
distance
,
allDist
=
pool
.
getBuffer
(
nQuery
,
nTrain
,
CV_32FC1
);
const
GpuMat
&
maskCollection
,
Stream
&
stream
)
}
{
if
(
query
.
empty
()
||
trainCollection
.
empty
())
return
;
using
namespace
cv
::
cuda
::
device
::
bf_knnmatch
;
trainIdx
.
setTo
(
Scalar
::
all
(
-
1
),
stream
)
;
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
trains
,
const
PtrStepSz
<
PtrStepb
>&
masks
,
func
(
query
,
train
,
k
,
mask
,
trainIdx
,
distance
,
allDist
,
StreamAccessor
::
getStream
(
stream
));
const
PtrStepSzb
&
trainIdx
,
const
PtrStepSzb
&
imgIdx
,
const
PtrStepSzb
&
distance
,
}
cudaStream_t
stream
);
static
const
caller_t
callersL1
[]
=
void
BFMatcher_Impl
::
knnMatchAsync
(
InputArray
_queryDescriptors
,
{
OutputArray
_matches
,
match2L1_gpu
<
unsigned
char
>
,
0
/*match2L1_gpu<signed char>*/
,
int
k
,
match2L1_gpu
<
unsigned
short
>
,
match2L1_gpu
<
short
>
,
const
std
::
vector
<
GpuMat
>&
masks
,
match2L1_gpu
<
int
>
,
match2L1_gpu
<
float
>
Stream
&
stream
)
};
static
const
caller_t
callersL2
[]
=
{
0
/*match2L2_gpu<unsigned char>*/
,
0
/*match2L2_gpu<signed char>*/
,
0
/*match2L2_gpu<unsigned short>*/
,
0
/*match2L2_gpu<short>*/
,
0
/*match2L2_gpu<int>*/
,
match2L2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
{
match2Hamming_gpu
<
unsigned
char
>
,
0
/*match2Hamming_gpu<signed char>*/
,
using
namespace
cv
::
cuda
::
device
::
bf_knnmatch
;
match2Hamming_gpu
<
unsigned
short
>
,
0
/*match2Hamming_gpu<short>*/
,
match2Hamming_gpu
<
int
>
,
0
/*match2Hamming_gpu<float>*/
};
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
CV_Assert
(
norm
==
NORM_L1
||
norm
==
NORM_L2
||
norm
==
NORM_HAMMING
);
const
caller_t
*
callers
=
norm
==
NORM_L1
?
callersL1
:
norm
==
NORM_L2
?
callersL2
:
callersHamming
;
if
(
k
!=
2
)
{
CV_Error
(
Error
::
StsNotImplemented
,
"only k=2 mode is supported for now"
);
}
const
int
nQuery
=
query
.
rows
;
const
GpuMat
query
=
_queryDescriptors
.
getGpuMat
()
;
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32SC2
,
trainIdx
);
if
(
query
.
empty
()
||
trainDescCollection_
.
empty
())
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32SC2
,
imgIdx
);
{
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32FC2
,
distance
);
_matches
.
release
();
return
;
}
trainIdx
.
setTo
(
Scalar
::
all
(
-
1
),
stream
);
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
caller_t
func
=
callers
[
query
.
depth
()]
;
GpuMat
trainCollection
,
maskCollection
;
CV_Assert
(
func
!=
0
);
makeGpuCollection
(
trainDescCollection_
,
masks
,
trainCollection
,
maskCollection
);
func
(
query
,
trainCollection
,
maskCollection
,
trainIdx
,
imgIdx
,
distance
,
StreamAccessor
::
getStream
(
stream
));
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
trains
,
const
PtrStepSz
<
PtrStepb
>&
masks
,
}
const
PtrStepSzb
&
trainIdx
,
const
PtrStepSzb
&
imgIdx
,
const
PtrStepSzb
&
distance
,
cudaStream_t
stream
);
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch2Download
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
imgIdx
,
const
GpuMat
&
distance
,
static
const
caller_t
callersL1
[]
=
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
{
{
match2L1_gpu
<
unsigned
char
>
,
0
/*match2L1_gpu<signed char>*/
,
if
(
trainIdx
.
empty
()
||
imgIdx
.
empty
()
||
distance
.
empty
())
match2L1_gpu
<
unsigned
short
>
,
match2L1_gpu
<
short
>
,
return
;
match2L1_gpu
<
int
>
,
match2L1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
0
/*match2L2_gpu<unsigned char>*/
,
0
/*match2L2_gpu<signed char>*/
,
0
/*match2L2_gpu<unsigned short>*/
,
0
/*match2L2_gpu<short>*/
,
0
/*match2L2_gpu<int>*/
,
match2L2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
match2Hamming_gpu
<
unsigned
char
>
,
0
/*match2Hamming_gpu<signed char>*/
,
match2Hamming_gpu
<
unsigned
short
>
,
0
/*match2Hamming_gpu<short>*/
,
match2Hamming_gpu
<
int
>
,
0
/*match2Hamming_gpu<float>*/
};
Mat
trainIdxCPU
(
trainIdx
);
const
caller_t
*
callers
=
norm_
==
NORM_L1
?
callersL1
:
norm_
==
NORM_L2
?
callersL2
:
callersHamming
;
Mat
imgIdxCPU
(
imgIdx
);
Mat
distanceCPU
(
distance
);
knnMatch2Convert
(
trainIdxCPU
,
imgIdxCPU
,
distanceCPU
,
matches
,
compactResult
);
const
caller_t
func
=
callers
[
query
.
depth
()];
}
if
(
func
==
0
)
{
CV_Error
(
Error
::
StsUnsupportedFormat
,
"unsupported combination of query.depth() and norm"
);
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch2Convert
(
const
Mat
&
trainIdx
,
const
Mat
&
imgIdx
,
const
Mat
&
distance
,
const
int
nQuery
=
query
.
rows
;
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
{
if
(
trainIdx
.
empty
()
||
imgIdx
.
empty
()
||
distance
.
empty
())
return
;
CV_Assert
(
trainIdx
.
type
()
==
CV_32SC2
);
_matches
.
create
(
3
,
nQuery
,
CV_32SC2
);
CV_Assert
(
imgIdx
.
type
()
==
CV_32SC2
&&
imgIdx
.
cols
==
trainIdx
.
cols
);
GpuMat
matches
=
_matches
.
getGpuMat
();
CV_Assert
(
distance
.
type
()
==
CV_32FC2
&&
distance
.
cols
==
trainIdx
.
cols
);
const
int
nQuery
=
trainIdx
.
cols
;
GpuMat
trainIdx
(
1
,
nQuery
,
CV_32SC2
,
matches
.
ptr
(
0
));
GpuMat
imgIdx
(
1
,
nQuery
,
CV_32SC2
,
matches
.
ptr
(
1
));
GpuMat
distance
(
1
,
nQuery
,
CV_32FC2
,
matches
.
ptr
(
2
));
matches
.
clear
();
trainIdx
.
setTo
(
Scalar
::
all
(
-
1
),
stream
);
matches
.
reserve
(
nQuery
);
const
int
*
trainIdx_ptr
=
trainIdx
.
ptr
<
int
>
();
func
(
query
,
trainCollection
,
maskCollection
,
trainIdx
,
imgIdx
,
distance
,
StreamAccessor
::
getStream
(
stream
));
const
int
*
imgIdx_ptr
=
imgIdx
.
ptr
<
int
>
();
}
const
float
*
distance_ptr
=
distance
.
ptr
<
float
>
();
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
)
void
BFMatcher_Impl
::
knnMatchConvert
(
InputArray
_gpu_matches
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
{
{
matches
.
push_back
(
std
::
vector
<
DMatch
>
());
Mat
gpu_matches
;
std
::
vector
<
DMatch
>&
curMatches
=
matches
.
back
();
if
(
_gpu_matches
.
kind
()
==
_InputArray
::
CUDA_GPU_MAT
)
curMatches
.
reserve
(
2
);
for
(
int
i
=
0
;
i
<
2
;
++
i
,
++
trainIdx_ptr
,
++
imgIdx_ptr
,
++
distance_ptr
)
{
{
int
_trainIdx
=
*
trainIdx_ptr
;
_gpu_matches
.
getGpuMat
().
download
(
gpu_matches
);
}
if
(
_trainIdx
!=
-
1
)
else
{
{
int
_imgIdx
=
*
imgIdx_ptr
;
gpu_matches
=
_gpu_matches
.
getMat
();
float
_distance
=
*
distance_ptr
;
DMatch
m
(
queryIdx
,
_trainIdx
,
_imgIdx
,
_distance
);
curMatches
.
push_back
(
m
);
}
}
}
if
(
compactResult
&&
curMatches
.
empty
())
if
(
gpu_matches
.
empty
())
matches
.
pop_back
();
{
}
matches
.
clear
();
}
return
;
}
namespace
CV_Assert
(
((
gpu_matches
.
type
()
==
CV_32SC2
)
&&
(
gpu_matches
.
rows
==
2
||
gpu_matches
.
rows
==
3
))
||
{
(
gpu_matches
.
type
()
==
CV_32SC1
)
);
struct
ImgIdxSetter
{
explicit
inline
ImgIdxSetter
(
int
imgIdx_
)
:
imgIdx
(
imgIdx_
)
{}
inline
void
operator
()(
DMatch
&
m
)
const
{
m
.
imgIdx
=
imgIdx
;}
int
imgIdx
;
};
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
knnMatch
(
const
GpuMat
&
query
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
int
k
,
int
nQuery
=
-
1
,
k
=
-
1
;
const
std
::
vector
<
GpuMat
>&
masks
,
bool
compactResult
)
{
if
(
k
==
2
)
{
GpuMat
trainCollection
;
GpuMat
maskCollection
;
makeGpuCollection
(
trainCollection
,
maskCollection
,
masks
);
const
int
*
trainIdxPtr
=
NULL
;
const
int
*
imgIdxPtr
=
NULL
;
const
float
*
distancePtr
=
NULL
;
GpuMat
trainIdx
,
imgIdx
,
distance
;
if
(
gpu_matches
.
type
()
==
CV_32SC2
)
{
nQuery
=
gpu_matches
.
cols
;
k
=
2
;
knnMatch2Collection
(
query
,
trainCollection
,
trainIdx
,
imgIdx
,
distance
,
maskCollection
);
if
(
gpu_matches
.
rows
==
2
)
knnMatch2Download
(
trainIdx
,
imgIdx
,
distance
,
matches
);
{
}
trainIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
0
);
else
distancePtr
=
gpu_matches
.
ptr
<
float
>
(
1
);
{
}
if
(
query
.
empty
()
||
empty
())
else
return
;
{
trainIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
0
);
imgIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
1
);
distancePtr
=
gpu_matches
.
ptr
<
float
>
(
2
);
}
}
else
{
nQuery
=
gpu_matches
.
rows
/
2
;
k
=
gpu_matches
.
cols
;
std
::
vector
<
std
::
vector
<
DMatch
>
>
curMatches
;
trainIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
0
)
;
std
::
vector
<
DMatch
>
temp
;
distancePtr
=
gpu_matches
.
ptr
<
float
>
(
nQuery
)
;
temp
.
reserve
(
2
*
k
);
}
matches
.
resize
(
query
.
rows
);
matches
.
clear
(
);
for_each
(
matches
.
begin
(),
matches
.
end
(),
bind2nd
(
mem_fun_ref
(
&
std
::
vector
<
DMatch
>::
reserve
),
k
)
);
matches
.
reserve
(
nQuery
);
for
(
size_t
imgIdx
=
0
,
size
=
trainDescCollection
.
size
();
imgIdx
<
size
;
++
img
Idx
)
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
query
Idx
)
{
{
knnMatch
(
query
,
trainDescCollection
[
imgIdx
],
curMatches
,
k
,
masks
.
empty
()
?
GpuMat
()
:
masks
[
imgIdx
]);
matches
.
push_back
(
std
::
vector
<
DMatch
>
());
std
::
vector
<
DMatch
>&
curMatches
=
matches
.
back
();
curMatches
.
reserve
(
k
);
for
(
int
queryIdx
=
0
;
queryIdx
<
query
.
rows
;
++
queryIdx
)
for
(
int
i
=
0
;
i
<
k
;
++
i
)
{
{
std
::
vector
<
DMatch
>&
localMatch
=
curMatches
[
queryIdx
];
const
int
trainIdx
=
*
trainIdxPtr
;
std
::
vector
<
DMatch
>&
globalMatch
=
matches
[
queryIdx
];
if
(
trainIdx
==
-
1
)
continue
;
for_each
(
localMatch
.
begin
(),
localMatch
.
end
(),
ImgIdxSetter
(
static_cast
<
int
>
(
imgIdx
)));
const
int
imgIdx
=
imgIdxPtr
?
*
imgIdxPtr
:
0
;
const
float
distance
=
*
distancePtr
;
temp
.
clear
();
DMatch
m
(
queryIdx
,
trainIdx
,
imgIdx
,
distance
);
merge
(
globalMatch
.
begin
(),
globalMatch
.
end
(),
localMatch
.
begin
(),
localMatch
.
end
(),
back_inserter
(
temp
));
curMatches
.
push_back
(
m
);
globalMatch
.
clear
();
++
trainIdxPtr
;
const
size_t
count
=
std
::
min
((
size_t
)
k
,
temp
.
size
());
++
distancePtr
;
copy
(
temp
.
begin
(),
temp
.
begin
()
+
count
,
back_inserter
(
globalMatch
));
if
(
imgIdxPtr
)
++
imgIdxPtr
;
}
}
}
if
(
compactResult
)
if
(
compactResult
&&
curMatches
.
empty
()
)
{
{
std
::
vector
<
std
::
vector
<
DMatch
>
>::
iterator
new_end
=
remove_if
(
matches
.
begin
(),
matches
.
end
(),
mem_fun_ref
(
&
std
::
vector
<
DMatch
>::
empty
)
);
matches
.
pop_back
(
);
matches
.
erase
(
new_end
,
matches
.
end
());
}
}
}
}
}
}
////////////////////////////////////////////////////////////////////
// RadiusMatch
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchSingle
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
GpuMat
&
trainIdx
,
GpuMat
&
distance
,
GpuMat
&
nMatches
,
float
maxDistance
,
const
GpuMat
&
mask
,
Stream
&
stream
)
{
if
(
query
.
empty
()
||
train
.
empty
())
return
;
using
namespace
cv
::
cuda
::
device
::
bf_radius_match
;
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
train
,
float
maxDistance
,
const
PtrStepSzb
&
mask
,
//
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzf
&
distance
,
const
PtrStepSz
<
unsigned
int
>&
nMatches
,
// radius match
cudaStream_t
stream
);
//
static
const
caller_t
callersL1
[]
=
void
BFMatcher_Impl
::
radiusMatch
(
InputArray
_queryDescriptors
,
InputArray
_trainDescriptors
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
InputArray
_mask
,
bool
compactResult
)
{
{
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
GpuMat
d_matches
;
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
radiusMatchAsync
(
_queryDescriptors
,
_trainDescriptors
,
d_matches
,
maxDistance
,
_mask
);
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
radiusMatchConvert
(
d_matches
,
matches
,
compactResult
);
};
}
static
const
caller_t
callersL2
[]
=
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
const
int
nQuery
=
query
.
rows
;
void
BFMatcher_Impl
::
radiusMatch
(
InputArray
_queryDescriptors
,
const
int
nTrain
=
train
.
rows
;
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
,
bool
compactResult
)
{
GpuMat
d_matches
;
radiusMatchAsync
(
_queryDescriptors
,
d_matches
,
maxDistance
,
masks
);
radiusMatchConvert
(
d_matches
,
matches
,
compactResult
);
}
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
void
BFMatcher_Impl
::
radiusMatchAsync
(
InputArray
_queryDescriptors
,
InputArray
_trainDescriptors
,
CV_Assert
(
train
.
type
()
==
query
.
type
()
&&
train
.
cols
==
query
.
cols
);
OutputArray
_matches
,
CV_Assert
(
trainIdx
.
empty
()
||
(
trainIdx
.
rows
==
nQuery
&&
trainIdx
.
size
()
==
distance
.
size
()));
float
maxDistance
,
CV_Assert
(
norm
==
NORM_L1
||
norm
==
NORM_L2
||
norm
==
NORM_HAMMING
);
InputArray
_mask
,
Stream
&
stream
)
{
using
namespace
cv
::
cuda
::
device
::
bf_radius_match
;
const
caller_t
*
callers
=
norm
==
NORM_L1
?
callersL1
:
norm
==
NORM_L2
?
callersL2
:
callersHamming
;
const
GpuMat
query
=
_queryDescriptors
.
getGpuMat
();
const
GpuMat
train
=
_trainDescriptors
.
getGpuMat
();
const
GpuMat
mask
=
_mask
.
getGpuMat
();
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32SC1
,
nMatches
);
if
(
query
.
empty
()
||
train
.
empty
())
if
(
trainIdx
.
empty
())
{
{
_matches
.
release
();
ensureSizeIsEnough
(
nQuery
,
std
::
max
((
nTrain
/
100
),
10
),
CV_32SC1
,
trainIdx
);
return
;
ensureSizeIsEnough
(
nQuery
,
std
::
max
((
nTrain
/
100
),
10
),
CV_32FC1
,
distance
);
}
}
nMatches
.
setTo
(
Scalar
::
all
(
0
),
stream
);
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
CV_Assert
(
train
.
cols
==
query
.
cols
&&
train
.
type
()
==
query
.
type
()
);
CV_Assert
(
mask
.
empty
()
||
(
mask
.
type
()
==
CV_8UC1
&&
mask
.
rows
==
query
.
rows
&&
mask
.
cols
==
train
.
rows
)
);
caller_t
func
=
callers
[
query
.
depth
()];
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
&
train
,
float
maxDistance
,
const
PtrStepSzb
&
mask
,
CV_Assert
(
func
!=
0
);
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzf
&
distance
,
const
PtrStepSz
<
unsigned
int
>&
nMatches
,
cudaStream_t
stream
);
func
(
query
,
train
,
maxDistance
,
mask
,
trainIdx
,
distance
,
nMatches
,
StreamAccessor
::
getStream
(
stream
));
static
const
caller_t
callersL1
[]
=
}
{
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
distance
,
const
GpuMat
&
nMatches
,
const
caller_t
*
callers
=
norm_
==
NORM_L1
?
callersL1
:
norm_
==
NORM_L2
?
callersL2
:
callersHamming
;
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
{
if
(
trainIdx
.
empty
()
||
distance
.
empty
()
||
nMatches
.
empty
())
return
;
Mat
trainIdxCPU
(
trainIdx
);
const
caller_t
func
=
callers
[
query
.
depth
()];
Mat
distanceCPU
(
distance
);
if
(
func
==
0
)
Mat
nMatchesCPU
(
nMatches
);
{
CV_Error
(
Error
::
StsUnsupportedFormat
,
"unsupported combination of query.depth() and norm"
);
}
radiusMatchConvert
(
trainIdxCPU
,
distanceCPU
,
nMatchesCPU
,
matches
,
compactResult
)
;
const
int
nQuery
=
query
.
rows
;
}
const
int
nTrain
=
train
.
rows
;
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
distance
,
const
Mat
&
nMatches
,
const
int
cols
=
std
::
max
((
nTrain
/
100
),
nQuery
);
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
{
if
(
trainIdx
.
empty
()
||
distance
.
empty
()
||
nMatches
.
empty
())
return
;
CV_Assert
(
trainIdx
.
type
()
==
CV_32SC1
);
_matches
.
create
(
2
*
nQuery
+
1
,
cols
,
CV_32SC1
);
CV_Assert
(
distance
.
type
()
==
CV_32FC1
&&
distance
.
size
()
==
trainIdx
.
size
());
GpuMat
matches
=
_matches
.
getGpuMat
();
CV_Assert
(
nMatches
.
type
()
==
CV_32SC1
&&
nMatches
.
cols
==
trainIdx
.
rows
);
const
int
nQuery
=
trainIdx
.
rows
;
GpuMat
trainIdx
(
nQuery
,
cols
,
CV_32SC1
,
matches
.
ptr
(
0
),
matches
.
step
);
GpuMat
distance
(
nQuery
,
cols
,
CV_32FC1
,
matches
.
ptr
(
nQuery
),
matches
.
step
);
GpuMat
nMatches
(
1
,
nQuery
,
CV_32SC1
,
matches
.
ptr
(
2
*
nQuery
));
matches
.
clear
();
nMatches
.
setTo
(
Scalar
::
all
(
0
),
stream
);
matches
.
reserve
(
nQuery
);
const
int
*
nMatches_ptr
=
nMatches
.
ptr
<
int
>
();
func
(
query
,
train
,
maxDistance
,
mask
,
trainIdx
,
distance
,
nMatches
,
StreamAccessor
::
getStream
(
stream
));
}
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
)
void
BFMatcher_Impl
::
radiusMatchAsync
(
InputArray
_queryDescriptors
,
OutputArray
_matches
,
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
,
Stream
&
stream
)
{
{
const
int
*
trainIdx_ptr
=
trainIdx
.
ptr
<
int
>
(
queryIdx
);
using
namespace
cv
::
cuda
::
device
::
bf_radius_match
;
const
float
*
distance_ptr
=
distance
.
ptr
<
float
>
(
queryIdx
);
const
int
nMatched
=
std
::
min
(
nMatches_ptr
[
queryIdx
],
trainIdx
.
cols
);
const
GpuMat
query
=
_queryDescriptors
.
getGpuMat
(
);
if
(
nMatched
==
0
)
if
(
query
.
empty
()
||
trainDescCollection_
.
empty
()
)
{
{
if
(
!
compactResult
)
_matches
.
release
();
matches
.
push_back
(
std
::
vector
<
DMatch
>
());
return
;
continue
;
}
}
matches
.
push_back
(
std
::
vector
<
DMatch
>
(
nMatched
));
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
std
::
vector
<
DMatch
>&
curMatches
=
matches
.
back
();
for
(
int
i
=
0
;
i
<
nMatched
;
++
i
,
++
trainIdx_ptr
,
++
distance_ptr
)
{
int
_trainIdx
=
*
trainIdx_ptr
;
float
_distance
=
*
distance_ptr
;
GpuMat
trainCollection
,
maskCollection
;
makeGpuCollection
(
trainDescCollection_
,
masks
,
trainCollection
,
maskCollection
);
DMatch
m
(
queryIdx
,
_trainIdx
,
0
,
_distance
);
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
*
trains
,
int
n
,
float
maxDistance
,
const
PtrStepSzb
*
masks
,
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzi
&
imgIdx
,
const
PtrStepSzf
&
distance
,
const
PtrStepSz
<
unsigned
int
>&
nMatches
,
curMatches
[
i
]
=
m
;
cudaStream_t
stream
);
}
sort
(
curMatches
.
begin
(),
curMatches
.
end
());
static
const
caller_t
callersL1
[]
=
}
{
}
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatch
(
const
GpuMat
&
query
,
const
GpuMat
&
train
,
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
const
GpuMat
&
mask
,
bool
compactResult
)
};
{
static
const
caller_t
callersL2
[]
=
GpuMat
trainIdx
,
distance
,
nMatches
;
{
radiusMatchSingle
(
query
,
train
,
trainIdx
,
distance
,
nMatches
,
maxDistance
,
mask
);
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
radiusMatchDownload
(
trainIdx
,
distance
,
nMatches
,
matches
,
compactResult
);
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
}
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchCollection
(
const
GpuMat
&
query
,
GpuMat
&
trainIdx
,
GpuMat
&
imgIdx
,
GpuMat
&
distance
,
GpuMat
&
nMatches
,
const
caller_t
*
callers
=
norm_
==
NORM_L1
?
callersL1
:
norm_
==
NORM_L2
?
callersL2
:
callersHamming
;
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
,
Stream
&
stream
)
{
if
(
query
.
empty
()
||
empty
())
return
;
using
namespace
cv
::
cuda
::
device
::
bf_radius_match
;
const
caller_t
func
=
callers
[
query
.
depth
()];
if
(
func
==
0
)
{
CV_Error
(
Error
::
StsUnsupportedFormat
,
"unsupported combination of query.depth() and norm"
);
}
typedef
void
(
*
caller_t
)(
const
PtrStepSzb
&
query
,
const
PtrStepSzb
*
trains
,
int
n
,
float
maxDistance
,
const
PtrStepSzb
*
masks
,
const
int
nQuery
=
query
.
rows
;
const
PtrStepSzi
&
trainIdx
,
const
PtrStepSzi
&
imgIdx
,
const
PtrStepSzf
&
distance
,
const
PtrStepSz
<
unsigned
int
>&
nMatches
,
cudaStream_t
stream
);
static
const
caller_t
callersL1
[]
=
_matches
.
create
(
3
*
nQuery
+
1
,
nQuery
,
CV_32FC1
);
{
GpuMat
matches
=
_matches
.
getGpuMat
();
matchL1_gpu
<
unsigned
char
>
,
0
/*matchL1_gpu<signed char>*/
,
matchL1_gpu
<
unsigned
short
>
,
matchL1_gpu
<
short
>
,
matchL1_gpu
<
int
>
,
matchL1_gpu
<
float
>
};
static
const
caller_t
callersL2
[]
=
{
0
/*matchL2_gpu<unsigned char>*/
,
0
/*matchL2_gpu<signed char>*/
,
0
/*matchL2_gpu<unsigned short>*/
,
0
/*matchL2_gpu<short>*/
,
0
/*matchL2_gpu<int>*/
,
matchL2_gpu
<
float
>
};
static
const
caller_t
callersHamming
[]
=
{
matchHamming_gpu
<
unsigned
char
>
,
0
/*matchHamming_gpu<signed char>*/
,
matchHamming_gpu
<
unsigned
short
>
,
0
/*matchHamming_gpu<short>*/
,
matchHamming_gpu
<
int
>
,
0
/*matchHamming_gpu<float>*/
};
const
int
nQuery
=
query
.
rows
;
GpuMat
trainIdx
(
nQuery
,
nQuery
,
CV_32SC1
,
matches
.
ptr
(
0
),
matches
.
step
);
GpuMat
imgIdx
(
nQuery
,
nQuery
,
CV_32SC1
,
matches
.
ptr
(
nQuery
),
matches
.
step
);
GpuMat
distance
(
nQuery
,
nQuery
,
CV_32FC1
,
matches
.
ptr
(
2
*
nQuery
),
matches
.
step
);
GpuMat
nMatches
(
1
,
nQuery
,
CV_32SC1
,
matches
.
ptr
(
3
*
nQuery
));
CV_Assert
(
query
.
channels
()
==
1
&&
query
.
depth
()
<
CV_64F
);
nMatches
.
setTo
(
Scalar
::
all
(
0
),
stream
);
CV_Assert
(
trainIdx
.
empty
()
||
(
trainIdx
.
rows
==
nQuery
&&
trainIdx
.
size
()
==
distance
.
size
()
&&
trainIdx
.
size
()
==
imgIdx
.
size
()));
CV_Assert
(
norm
==
NORM_L1
||
norm
==
NORM_L2
||
norm
==
NORM_HAMMING
);
const
caller_t
*
callers
=
norm
==
NORM_L1
?
callersL1
:
norm
==
NORM_L2
?
callersL2
:
callersHamming
;
std
::
vector
<
PtrStepSzb
>
trains_
(
trainDescCollection_
.
begin
(),
trainDescCollection_
.
end
());
std
::
vector
<
PtrStepSzb
>
masks_
(
masks
.
begin
(),
masks
.
end
());
ensureSizeIsEnough
(
1
,
nQuery
,
CV_32SC1
,
nMatches
);
func
(
query
,
&
trains_
[
0
],
static_cast
<
int
>
(
trains_
.
size
()),
maxDistance
,
masks_
.
size
()
==
0
?
0
:
&
masks_
[
0
],
if
(
trainIdx
.
empty
())
trainIdx
,
imgIdx
,
distance
,
nMatches
,
StreamAccessor
::
getStream
(
stream
));
{
ensureSizeIsEnough
(
nQuery
,
std
::
max
((
nQuery
/
100
),
10
),
CV_32SC1
,
trainIdx
);
ensureSizeIsEnough
(
nQuery
,
std
::
max
((
nQuery
/
100
),
10
),
CV_32SC1
,
imgIdx
);
ensureSizeIsEnough
(
nQuery
,
std
::
max
((
nQuery
/
100
),
10
),
CV_32FC1
,
distance
);
}
}
nMatches
.
setTo
(
Scalar
::
all
(
0
),
stream
);
void
BFMatcher_Impl
::
radiusMatchConvert
(
InputArray
_gpu_matches
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
caller_t
func
=
callers
[
query
.
depth
()];
bool
compactResult
)
CV_Assert
(
func
!=
0
);
{
Mat
gpu_matches
;
std
::
vector
<
PtrStepSzb
>
trains_
(
trainDescCollection
.
begin
(),
trainDescCollection
.
end
());
if
(
_gpu_matches
.
kind
()
==
_InputArray
::
CUDA_GPU_MAT
)
std
::
vector
<
PtrStepSzb
>
masks_
(
masks
.
begin
(),
masks
.
end
());
{
_gpu_matches
.
getGpuMat
().
download
(
gpu_matches
);
}
else
{
gpu_matches
=
_gpu_matches
.
getMat
();
}
func
(
query
,
&
trains_
[
0
],
static_cast
<
int
>
(
trains_
.
size
()),
maxDistance
,
masks_
.
size
()
==
0
?
0
:
&
masks_
[
0
],
if
(
gpu_matches
.
empty
())
trainIdx
,
imgIdx
,
distance
,
nMatches
,
StreamAccessor
::
getStream
(
stream
));
{
}
matches
.
clear
();
return
;
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchDownload
(
const
GpuMat
&
trainIdx
,
const
GpuMat
&
imgIdx
,
const
GpuMat
&
distance
,
const
GpuMat
&
nMatches
,
CV_Assert
(
gpu_matches
.
type
()
==
CV_32SC1
||
gpu_matches
.
type
()
==
CV_32FC1
);
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
{
if
(
trainIdx
.
empty
()
||
imgIdx
.
empty
()
||
distance
.
empty
()
||
nMatches
.
empty
())
return
;
Mat
trainIdxCPU
(
trainIdx
);
int
nQuery
=
-
1
;
Mat
imgIdxCPU
(
imgIdx
);
Mat
distanceCPU
(
distance
);
Mat
nMatchesCPU
(
nMatches
);
radiusMatchConvert
(
trainIdxCPU
,
imgIdxCPU
,
distanceCPU
,
nMatchesCPU
,
matches
,
compactResult
);
const
int
*
trainIdxPtr
=
NULL
;
}
const
int
*
imgIdxPtr
=
NULL
;
const
float
*
distancePtr
=
NULL
;
const
int
*
nMatchesPtr
=
NULL
;
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatchConvert
(
const
Mat
&
trainIdx
,
const
Mat
&
imgIdx
,
const
Mat
&
distance
,
const
Mat
&
nMatches
,
if
(
gpu_matches
.
type
()
==
CV_32SC1
)
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
bool
compactResult
)
{
{
nQuery
=
(
gpu_matches
.
rows
-
1
)
/
2
;
if
(
trainIdx
.
empty
()
||
imgIdx
.
empty
()
||
distance
.
empty
()
||
nMatches
.
empty
())
return
;
CV_Assert
(
trainIdx
.
type
()
==
CV_32SC1
);
trainIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
0
);
CV_Assert
(
imgIdx
.
type
()
==
CV_32SC1
&&
imgIdx
.
size
()
==
trainIdx
.
size
());
distancePtr
=
gpu_matches
.
ptr
<
float
>
(
nQuery
);
CV_Assert
(
distance
.
type
()
==
CV_32FC1
&&
distance
.
size
()
==
trainIdx
.
size
());
nMatchesPtr
=
gpu_matches
.
ptr
<
int
>
(
2
*
nQuery
);
CV_Assert
(
nMatches
.
type
()
==
CV_32SC1
&&
nMatches
.
cols
==
trainIdx
.
rows
);
}
else
{
nQuery
=
(
gpu_matches
.
rows
-
1
)
/
3
;
const
int
nQuery
=
trainIdx
.
rows
;
trainIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
0
);
imgIdxPtr
=
gpu_matches
.
ptr
<
int
>
(
nQuery
);
distancePtr
=
gpu_matches
.
ptr
<
float
>
(
2
*
nQuery
);
nMatchesPtr
=
gpu_matches
.
ptr
<
int
>
(
3
*
nQuery
);
}
matches
.
clear
();
matches
.
clear
();
matches
.
reserve
(
nQuery
);
matches
.
reserve
(
nQuery
);
const
int
*
nMatches_ptr
=
nMatches
.
ptr
<
int
>
();
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
)
{
const
int
nMatched
=
std
::
min
(
nMatchesPtr
[
queryIdx
],
gpu_matches
.
cols
);
for
(
int
queryIdx
=
0
;
queryIdx
<
nQuery
;
++
queryIdx
)
if
(
nMatched
==
0
)
{
{
const
int
*
trainIdx_ptr
=
trainIdx
.
ptr
<
int
>
(
queryIdx
);
if
(
!
compactResult
)
const
int
*
imgIdx_ptr
=
imgIdx
.
ptr
<
int
>
(
queryIdx
);
{
const
float
*
distance_ptr
=
distance
.
ptr
<
float
>
(
queryIdx
);
matches
.
push_back
(
std
::
vector
<
DMatch
>
());
}
}
else
{
matches
.
push_back
(
std
::
vector
<
DMatch
>
(
nMatched
));
std
::
vector
<
DMatch
>&
curMatches
=
matches
.
back
();
const
int
nMatched
=
std
::
min
(
nMatches_ptr
[
queryIdx
],
trainIdx
.
cols
);
for
(
int
i
=
0
;
i
<
nMatched
;
++
i
)
{
const
int
trainIdx
=
trainIdxPtr
[
i
];
if
(
nMatched
==
0
)
const
int
imgIdx
=
imgIdxPtr
?
imgIdxPtr
[
i
]
:
0
;
{
const
float
distance
=
distancePtr
[
i
];
if
(
!
compactResult
)
matches
.
push_back
(
std
::
vector
<
DMatch
>
());
continue
;
}
matches
.
push_back
(
std
::
vector
<
DMatch
>
());
DMatch
m
(
queryIdx
,
trainIdx
,
imgIdx
,
distance
);
std
::
vector
<
DMatch
>&
curMatches
=
matches
.
back
();
curMatches
.
reserve
(
nMatched
);
for
(
int
i
=
0
;
i
<
nMatched
;
++
i
,
++
trainIdx_ptr
,
++
imgIdx_ptr
,
++
distance_ptr
)
curMatches
[
i
]
=
m
;
{
}
int
_trainIdx
=
*
trainIdx_ptr
;
int
_imgIdx
=
*
imgIdx_ptr
;
float
_distance
=
*
distance_ptr
;
DMatch
m
(
queryIdx
,
_trainIdx
,
_imgIdx
,
_distance
);
std
::
sort
(
curMatches
.
begin
(),
curMatches
.
end
());
}
curMatches
.
push_back
(
m
);
trainIdxPtr
+=
gpu_matches
.
cols
;
distancePtr
+=
gpu_matches
.
cols
;
if
(
imgIdxPtr
)
imgIdxPtr
+=
gpu_matches
.
cols
;
}
}
sort
(
curMatches
.
begin
(),
curMatches
.
end
());
}
}
}
}
void
cv
::
cuda
::
BFMatcher_CUDA
::
radiusMatch
(
const
GpuMat
&
query
,
std
::
vector
<
std
::
vector
<
DMatch
>
>&
matches
,
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
int
norm
)
float
maxDistance
,
const
std
::
vector
<
GpuMat
>&
masks
,
bool
compactResult
)
{
{
GpuMat
trainIdx
,
imgIdx
,
distance
,
nMatches
;
return
makePtr
<
BFMatcher_Impl
>
(
norm
);
radiusMatchCollection
(
query
,
trainIdx
,
imgIdx
,
distance
,
nMatches
,
maxDistance
,
masks
);
radiusMatchDownload
(
trainIdx
,
imgIdx
,
distance
,
nMatches
,
matches
,
compactResult
);
}
}
#endif
/* !defined (HAVE_CUDA) */
#endif
/* !defined (HAVE_CUDA) */
modules/cudafeatures2d/test/test_features2d.cpp
View file @
8a178da1
...
@@ -285,7 +285,8 @@ PARAM_TEST_CASE(BruteForceMatcher, cv::cuda::DeviceInfo, NormCode, DescriptorSiz
...
@@ -285,7 +285,8 @@ PARAM_TEST_CASE(BruteForceMatcher, cv::cuda::DeviceInfo, NormCode, DescriptorSiz
CUDA_TEST_P
(
BruteForceMatcher
,
Match_Single
)
CUDA_TEST_P
(
BruteForceMatcher
,
Match_Single
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
cv
::
cuda
::
GpuMat
mask
;
cv
::
cuda
::
GpuMat
mask
;
if
(
useMask
)
if
(
useMask
)
...
@@ -295,7 +296,7 @@ CUDA_TEST_P(BruteForceMatcher, Match_Single)
...
@@ -295,7 +296,7 @@ CUDA_TEST_P(BruteForceMatcher, Match_Single)
}
}
std
::
vector
<
cv
::
DMatch
>
matches
;
std
::
vector
<
cv
::
DMatch
>
matches
;
matcher
.
match
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
mask
);
matcher
->
match
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
mask
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
@@ -312,13 +313,14 @@ CUDA_TEST_P(BruteForceMatcher, Match_Single)
...
@@ -312,13 +313,14 @@ CUDA_TEST_P(BruteForceMatcher, Match_Single)
CUDA_TEST_P
(
BruteForceMatcher
,
Match_Collection
)
CUDA_TEST_P
(
BruteForceMatcher
,
Match_Collection
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
cv
::
cuda
::
GpuMat
d_train
(
train
);
cv
::
cuda
::
GpuMat
d_train
(
train
);
// make add() twice to test such case
// make add() twice to test such case
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
// prepare masks (make first nearest match illegal)
// prepare masks (make first nearest match illegal)
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
...
@@ -331,9 +333,9 @@ CUDA_TEST_P(BruteForceMatcher, Match_Collection)
...
@@ -331,9 +333,9 @@ CUDA_TEST_P(BruteForceMatcher, Match_Collection)
std
::
vector
<
cv
::
DMatch
>
matches
;
std
::
vector
<
cv
::
DMatch
>
matches
;
if
(
useMask
)
if
(
useMask
)
matcher
.
match
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
masks
);
matcher
->
match
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
masks
);
else
else
matcher
.
match
(
cv
::
cuda
::
GpuMat
(
query
),
matches
);
matcher
->
match
(
cv
::
cuda
::
GpuMat
(
query
),
matches
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
@@ -366,7 +368,8 @@ CUDA_TEST_P(BruteForceMatcher, Match_Collection)
...
@@ -366,7 +368,8 @@ CUDA_TEST_P(BruteForceMatcher, Match_Collection)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_2_Single
)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_2_Single
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
const
int
knn
=
2
;
const
int
knn
=
2
;
...
@@ -378,7 +381,7 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Single)
...
@@ -378,7 +381,7 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Single)
}
}
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
matcher
.
knnMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
knn
,
mask
);
matcher
->
knnMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
knn
,
mask
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
@@ -405,7 +408,8 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Single)
...
@@ -405,7 +408,8 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Single)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_3_Single
)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_3_Single
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
const
int
knn
=
3
;
const
int
knn
=
3
;
...
@@ -417,7 +421,7 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Single)
...
@@ -417,7 +421,7 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Single)
}
}
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
matcher
.
knnMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
knn
,
mask
);
matcher
->
knnMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
knn
,
mask
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
@@ -444,15 +448,16 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Single)
...
@@ -444,15 +448,16 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Single)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_2_Collection
)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_2_Collection
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
const
int
knn
=
2
;
const
int
knn
=
2
;
cv
::
cuda
::
GpuMat
d_train
(
train
);
cv
::
cuda
::
GpuMat
d_train
(
train
);
// make add() twice to test such case
// make add() twice to test such case
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
// prepare masks (make first nearest match illegal)
// prepare masks (make first nearest match illegal)
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
...
@@ -466,9 +471,9 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Collection)
...
@@ -466,9 +471,9 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Collection)
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
if
(
useMask
)
if
(
useMask
)
matcher
.
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
,
masks
);
matcher
->
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
,
masks
);
else
else
matcher
.
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
);
matcher
->
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
@@ -506,15 +511,16 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Collection)
...
@@ -506,15 +511,16 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_2_Collection)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_3_Collection
)
CUDA_TEST_P
(
BruteForceMatcher
,
KnnMatch_3_Collection
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
const
int
knn
=
3
;
const
int
knn
=
3
;
cv
::
cuda
::
GpuMat
d_train
(
train
);
cv
::
cuda
::
GpuMat
d_train
(
train
);
// make add() twice to test such case
// make add() twice to test such case
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
// prepare masks (make first nearest match illegal)
// prepare masks (make first nearest match illegal)
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
...
@@ -528,9 +534,9 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Collection)
...
@@ -528,9 +534,9 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Collection)
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
if
(
useMask
)
if
(
useMask
)
matcher
.
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
,
masks
);
matcher
->
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
,
masks
);
else
else
matcher
.
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
);
matcher
->
knnMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
knn
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
@@ -568,7 +574,8 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Collection)
...
@@ -568,7 +574,8 @@ CUDA_TEST_P(BruteForceMatcher, KnnMatch_3_Collection)
CUDA_TEST_P
(
BruteForceMatcher
,
RadiusMatch_Single
)
CUDA_TEST_P
(
BruteForceMatcher
,
RadiusMatch_Single
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
const
float
radius
=
1.
f
/
countFactor
;
const
float
radius
=
1.
f
/
countFactor
;
...
@@ -577,7 +584,7 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Single)
...
@@ -577,7 +584,7 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Single)
try
try
{
{
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
matcher
.
radiusMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
radius
);
matcher
->
radiusMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
radius
);
}
}
catch
(
const
cv
::
Exception
&
e
)
catch
(
const
cv
::
Exception
&
e
)
{
{
...
@@ -594,7 +601,7 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Single)
...
@@ -594,7 +601,7 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Single)
}
}
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
matcher
.
radiusMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
radius
,
mask
);
matcher
->
radiusMatch
(
loadMat
(
query
),
loadMat
(
train
),
matches
,
radius
,
mask
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
@@ -617,7 +624,8 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Single)
...
@@ -617,7 +624,8 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Single)
CUDA_TEST_P
(
BruteForceMatcher
,
RadiusMatch_Collection
)
CUDA_TEST_P
(
BruteForceMatcher
,
RadiusMatch_Collection
)
{
{
cv
::
cuda
::
BFMatcher_CUDA
matcher
(
normCode
);
cv
::
Ptr
<
cv
::
cuda
::
DescriptorMatcher
>
matcher
=
cv
::
cuda
::
DescriptorMatcher
::
createBFMatcher
(
normCode
);
const
int
n
=
3
;
const
int
n
=
3
;
const
float
radius
=
1.
f
/
countFactor
*
n
;
const
float
radius
=
1.
f
/
countFactor
*
n
;
...
@@ -625,8 +633,8 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Collection)
...
@@ -625,8 +633,8 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Collection)
cv
::
cuda
::
GpuMat
d_train
(
train
);
cv
::
cuda
::
GpuMat
d_train
(
train
);
// make add() twice to test such case
// make add() twice to test such case
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
0
,
train
.
rows
/
2
)));
matcher
.
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
matcher
->
add
(
std
::
vector
<
cv
::
cuda
::
GpuMat
>
(
1
,
d_train
.
rowRange
(
train
.
rows
/
2
,
train
.
rows
)));
// prepare masks (make first nearest match illegal)
// prepare masks (make first nearest match illegal)
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
std
::
vector
<
cv
::
cuda
::
GpuMat
>
masks
(
2
);
...
@@ -642,7 +650,7 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Collection)
...
@@ -642,7 +650,7 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Collection)
try
try
{
{
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
matcher
.
radiusMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
radius
,
masks
);
matcher
->
radiusMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
radius
,
masks
);
}
}
catch
(
const
cv
::
Exception
&
e
)
catch
(
const
cv
::
Exception
&
e
)
{
{
...
@@ -654,9 +662,9 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Collection)
...
@@ -654,9 +662,9 @@ CUDA_TEST_P(BruteForceMatcher, RadiusMatch_Collection)
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
std
::
vector
<
std
::
vector
<
cv
::
DMatch
>
>
matches
;
if
(
useMask
)
if
(
useMask
)
matcher
.
radiusMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
radius
,
masks
);
matcher
->
radiusMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
radius
,
masks
);
else
else
matcher
.
radiusMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
radius
);
matcher
->
radiusMatch
(
cv
::
cuda
::
GpuMat
(
query
),
matches
,
radius
);
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
ASSERT_EQ
(
static_cast
<
size_t
>
(
queryDescCount
),
matches
.
size
());
...
...
modules/stitching/src/matchers.cpp
View file @
8a178da1
...
@@ -154,7 +154,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
...
@@ -154,7 +154,7 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
matches_info
.
matches
.
clear
();
matches_info
.
matches
.
clear
();
Ptr
<
DescriptorMatcher
>
matcher
;
Ptr
<
cv
::
DescriptorMatcher
>
matcher
;
#if 0 // TODO check this
#if 0 // TODO check this
if (ocl::useOpenCL())
if (ocl::useOpenCL())
{
{
...
@@ -220,13 +220,13 @@ void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
...
@@ -220,13 +220,13 @@ void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
descriptors1_
.
upload
(
features1
.
descriptors
);
descriptors1_
.
upload
(
features1
.
descriptors
);
descriptors2_
.
upload
(
features2
.
descriptors
);
descriptors2_
.
upload
(
features2
.
descriptors
);
BFMatcher_CUDA
matcher
(
NORM_L2
);
Ptr
<
cuda
::
DescriptorMatcher
>
matcher
=
cuda
::
DescriptorMatcher
::
createBFMatcher
(
NORM_L2
);
MatchesSet
matches
;
MatchesSet
matches
;
// Find 1->2 matches
// Find 1->2 matches
pair_matches
.
clear
();
pair_matches
.
clear
();
matcher
.
knnMatchSingle
(
descriptors1_
,
descriptors2_
,
train_idx_
,
distance_
,
all_dist_
,
2
);
matcher
->
knnMatch
(
descriptors1_
,
descriptors2_
,
pair_matches
,
2
);
matcher
.
knnMatchDownload
(
train_idx_
,
distance_
,
pair_matches
);
for
(
size_t
i
=
0
;
i
<
pair_matches
.
size
();
++
i
)
for
(
size_t
i
=
0
;
i
<
pair_matches
.
size
();
++
i
)
{
{
if
(
pair_matches
[
i
].
size
()
<
2
)
if
(
pair_matches
[
i
].
size
()
<
2
)
...
@@ -242,8 +242,7 @@ void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
...
@@ -242,8 +242,7 @@ void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
// Find 2->1 matches
// Find 2->1 matches
pair_matches
.
clear
();
pair_matches
.
clear
();
matcher
.
knnMatchSingle
(
descriptors2_
,
descriptors1_
,
train_idx_
,
distance_
,
all_dist_
,
2
);
matcher
->
knnMatch
(
descriptors2_
,
descriptors1_
,
pair_matches
,
2
);
matcher
.
knnMatchDownload
(
train_idx_
,
distance_
,
pair_matches
);
for
(
size_t
i
=
0
;
i
<
pair_matches
.
size
();
++
i
)
for
(
size_t
i
=
0
;
i
<
pair_matches
.
size
();
++
i
)
{
{
if
(
pair_matches
[
i
].
size
()
<
2
)
if
(
pair_matches
[
i
].
size
()
<
2
)
...
...
samples/gpu/performance/tests.cpp
View file @
8a178da1
...
@@ -379,14 +379,14 @@ TEST(BruteForceMatcher)
...
@@ -379,14 +379,14 @@ TEST(BruteForceMatcher)
// Init CUDA matcher
// Init CUDA matcher
cuda
::
BFMatcher_CUDA
d_m
atcher
(
NORM_L2
);
Ptr
<
cuda
::
DescriptorMatcher
>
d_matcher
=
cuda
::
DescriptorMatcher
::
createBFM
atcher
(
NORM_L2
);
cuda
::
GpuMat
d_query
(
query
);
cuda
::
GpuMat
d_query
(
query
);
cuda
::
GpuMat
d_train
(
train
);
cuda
::
GpuMat
d_train
(
train
);
// Output
// Output
vector
<
vector
<
DMatch
>
>
matches
(
2
);
vector
<
vector
<
DMatch
>
>
matches
(
2
);
cuda
::
GpuMat
d_
trainIdx
,
d_distance
,
d_allDist
,
d_nM
atches
;
cuda
::
GpuMat
d_
m
atches
;
SUBTEST
<<
"match"
;
SUBTEST
<<
"match"
;
...
@@ -396,10 +396,10 @@ TEST(BruteForceMatcher)
...
@@ -396,10 +396,10 @@ TEST(BruteForceMatcher)
matcher
.
match
(
query
,
train
,
matches
[
0
]);
matcher
.
match
(
query
,
train
,
matches
[
0
]);
CPU_OFF
;
CPU_OFF
;
d_matcher
.
matchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
);
d_matcher
->
matchAsync
(
d_query
,
d_train
,
d_matches
);
CUDA_ON
;
CUDA_ON
;
d_matcher
.
matchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
);
d_matcher
->
matchAsync
(
d_query
,
d_train
,
d_matches
);
CUDA_OFF
;
CUDA_OFF
;
SUBTEST
<<
"knnMatch"
;
SUBTEST
<<
"knnMatch"
;
...
@@ -410,10 +410,10 @@ TEST(BruteForceMatcher)
...
@@ -410,10 +410,10 @@ TEST(BruteForceMatcher)
matcher
.
knnMatch
(
query
,
train
,
matches
,
2
);
matcher
.
knnMatch
(
query
,
train
,
matches
,
2
);
CPU_OFF
;
CPU_OFF
;
d_matcher
.
knnMatchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
,
d_allDist
,
2
);
d_matcher
->
knnMatchAsync
(
d_query
,
d_train
,
d_matches
,
2
);
CUDA_ON
;
CUDA_ON
;
d_matcher
.
knnMatchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
,
d_allDist
,
2
);
d_matcher
->
knnMatchAsync
(
d_query
,
d_train
,
d_matches
,
2
);
CUDA_OFF
;
CUDA_OFF
;
SUBTEST
<<
"radiusMatch"
;
SUBTEST
<<
"radiusMatch"
;
...
@@ -426,12 +426,10 @@ TEST(BruteForceMatcher)
...
@@ -426,12 +426,10 @@ TEST(BruteForceMatcher)
matcher
.
radiusMatch
(
query
,
train
,
matches
,
max_distance
);
matcher
.
radiusMatch
(
query
,
train
,
matches
,
max_distance
);
CPU_OFF
;
CPU_OFF
;
d_trainIdx
.
release
();
d_matcher
->
radiusMatchAsync
(
d_query
,
d_train
,
d_matches
,
max_distance
);
d_matcher
.
radiusMatchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
,
d_nMatches
,
max_distance
);
CUDA_ON
;
CUDA_ON
;
d_matcher
.
radiusMatchSingle
(
d_query
,
d_train
,
d_trainIdx
,
d_distance
,
d_nM
atches
,
max_distance
);
d_matcher
->
radiusMatchAsync
(
d_query
,
d_train
,
d_m
atches
,
max_distance
);
CUDA_OFF
;
CUDA_OFF
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment