1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "precomp.hpp"
43 #include <limits>
44 #include "opencl_kernels_features2d.hpp"
45
46 #if defined(HAVE_EIGEN) && EIGEN_WORLD_VERSION == 2
47 #include <Eigen/Array>
48 #endif
49
50 namespace cv
51 {
52
53 /////////////////////// ocl functions for BFMatcher ///////////////////////////
54
ensureSizeIsEnough(int rows,int cols,int type,UMat & m)55 static void ensureSizeIsEnough(int rows, int cols, int type, UMat &m)
56 {
57 if (m.type() == type && m.rows >= rows && m.cols >= cols)
58 m = m(Rect(0, 0, cols, rows));
59 else
60 m.create(rows, cols, type);
61 }
62
ocl_matchSingle(InputArray query,InputArray train,UMat & trainIdx,UMat & distance,int distType)63 static bool ocl_matchSingle(InputArray query, InputArray train,
64 UMat &trainIdx, UMat &distance, int distType)
65 {
66 if (query.empty() || train.empty())
67 return false;
68
69 const int query_rows = query.rows();
70 const int query_cols = query.cols();
71
72 ensureSizeIsEnough(1, query_rows, CV_32S, trainIdx);
73 ensureSizeIsEnough(1, query_rows, CV_32F, distance);
74
75 ocl::Device devDef = ocl::Device::getDefault();
76
77 UMat uquery = query.getUMat(), utrain = train.getUMat();
78 int kercn = 1;
79 if (devDef.isIntel() &&
80 (0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&
81 (0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))
82 kercn = 4;
83
84 int block_size = 16;
85 int max_desc_len = 0;
86 bool is_cpu = devDef.type() == ocl::Device::TYPE_CPU;
87 if (query_cols <= 64)
88 max_desc_len = 64 / kercn;
89 else if (query_cols <= 128 && !is_cpu)
90 max_desc_len = 128 / kercn;
91
92 int depth = query.depth();
93 cv::String opts;
94 opts = cv::format("-D T=%s -D TN=%s -D kercn=%d %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d",
95 ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size, max_desc_len);
96 ocl::Kernel k("BruteForceMatch_Match", ocl::features2d::brute_force_match_oclsrc, opts);
97 if(k.empty())
98 return false;
99
100 size_t globalSize[] = {(query.size().height + block_size - 1) / block_size * block_size, block_size};
101 size_t localSize[] = {block_size, block_size};
102
103 int idx = 0;
104 idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));
105 idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));
106 idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));
107 idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));
108 idx = k.set(idx, uquery.rows);
109 idx = k.set(idx, uquery.cols);
110 idx = k.set(idx, utrain.rows);
111 idx = k.set(idx, utrain.cols);
112 idx = k.set(idx, (int)(uquery.step / sizeof(float)));
113
114 return k.run(2, globalSize, localSize, false);
115 }
116
ocl_matchConvert(const Mat & trainIdx,const Mat & distance,std::vector<std::vector<DMatch>> & matches)117 static bool ocl_matchConvert(const Mat &trainIdx, const Mat &distance, std::vector< std::vector<DMatch> > &matches)
118 {
119 if (trainIdx.empty() || distance.empty())
120 return false;
121
122 if( (trainIdx.type() != CV_32SC1) || (distance.type() != CV_32FC1 || distance.cols != trainIdx.cols) )
123 return false;
124
125 const int nQuery = trainIdx.cols;
126
127 matches.clear();
128 matches.reserve(nQuery);
129
130 const int *trainIdx_ptr = trainIdx.ptr<int>();
131 const float *distance_ptr = distance.ptr<float>();
132 for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx, ++trainIdx_ptr, ++distance_ptr)
133 {
134 int trainIndex = *trainIdx_ptr;
135
136 if (trainIndex == -1)
137 continue;
138
139 float dst = *distance_ptr;
140
141 DMatch m(queryIdx, trainIndex, 0, dst);
142
143 std::vector<DMatch> temp;
144 temp.push_back(m);
145 matches.push_back(temp);
146 }
147 return true;
148 }
149
ocl_matchDownload(const UMat & trainIdx,const UMat & distance,std::vector<std::vector<DMatch>> & matches)150 static bool ocl_matchDownload(const UMat &trainIdx, const UMat &distance, std::vector< std::vector<DMatch> > &matches)
151 {
152 if (trainIdx.empty() || distance.empty())
153 return false;
154
155 Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);
156 Mat distanceCPU = distance.getMat(ACCESS_READ);
157
158 return ocl_matchConvert(trainIdxCPU, distanceCPU, matches);
159 }
160
ocl_knnMatchSingle(InputArray query,InputArray train,UMat & trainIdx,UMat & distance,int distType)161 static bool ocl_knnMatchSingle(InputArray query, InputArray train, UMat &trainIdx,
162 UMat &distance, int distType)
163 {
164 if (query.empty() || train.empty())
165 return false;
166
167 const int query_rows = query.rows();
168 const int query_cols = query.cols();
169
170 ensureSizeIsEnough(1, query_rows, CV_32SC2, trainIdx);
171 ensureSizeIsEnough(1, query_rows, CV_32FC2, distance);
172
173 trainIdx.setTo(Scalar::all(-1));
174
175 ocl::Device devDef = ocl::Device::getDefault();
176
177 UMat uquery = query.getUMat(), utrain = train.getUMat();
178 int kercn = 1;
179 if (devDef.isIntel() &&
180 (0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&
181 (0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))
182 kercn = 4;
183
184 int block_size = 16;
185 int max_desc_len = 0;
186 bool is_cpu = devDef.type() == ocl::Device::TYPE_CPU;
187 if (query_cols <= 64)
188 max_desc_len = 64 / kercn;
189 else if (query_cols <= 128 && !is_cpu)
190 max_desc_len = 128 / kercn;
191
192 int depth = query.depth();
193 cv::String opts;
194 opts = cv::format("-D T=%s -D TN=%s -D kercn=%d %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d -D MAX_DESC_LEN=%d",
195 ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size, max_desc_len);
196 ocl::Kernel k("BruteForceMatch_knnMatch", ocl::features2d::brute_force_match_oclsrc, opts);
197 if(k.empty())
198 return false;
199
200 size_t globalSize[] = {(query_rows + block_size - 1) / block_size * block_size, block_size};
201 size_t localSize[] = {block_size, block_size};
202
203 int idx = 0;
204 idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));
205 idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));
206 idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));
207 idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));
208 idx = k.set(idx, uquery.rows);
209 idx = k.set(idx, uquery.cols);
210 idx = k.set(idx, utrain.rows);
211 idx = k.set(idx, utrain.cols);
212 idx = k.set(idx, (int)(uquery.step / sizeof(float)));
213
214 return k.run(2, globalSize, localSize, false);
215 }
216
ocl_knnMatchConvert(const Mat & trainIdx,const Mat & distance,std::vector<std::vector<DMatch>> & matches,bool compactResult)217 static bool ocl_knnMatchConvert(const Mat &trainIdx, const Mat &distance, std::vector< std::vector<DMatch> > &matches, bool compactResult)
218 {
219 if (trainIdx.empty() || distance.empty())
220 return false;
221
222 if(trainIdx.type() != CV_32SC2 && trainIdx.type() != CV_32SC1) return false;
223 if(distance.type() != CV_32FC2 && distance.type() != CV_32FC1)return false;
224 if(distance.size() != trainIdx.size()) return false;
225 if(!trainIdx.isContinuous() || !distance.isContinuous()) return false;
226
227 const int nQuery = trainIdx.type() == CV_32SC2 ? trainIdx.cols : trainIdx.rows;
228 const int k = trainIdx.type() == CV_32SC2 ? 2 : trainIdx.cols;
229
230 matches.clear();
231 matches.reserve(nQuery);
232
233 const int *trainIdx_ptr = trainIdx.ptr<int>();
234 const float *distance_ptr = distance.ptr<float>();
235
236 for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx)
237 {
238 matches.push_back(std::vector<DMatch>());
239 std::vector<DMatch> &curMatches = matches.back();
240 curMatches.reserve(k);
241
242 for (int i = 0; i < k; ++i, ++trainIdx_ptr, ++distance_ptr)
243 {
244 int trainIndex = *trainIdx_ptr;
245
246 if (trainIndex != -1)
247 {
248 float dst = *distance_ptr;
249
250 DMatch m(queryIdx, trainIndex, 0, dst);
251
252 curMatches.push_back(m);
253 }
254 }
255
256 if (compactResult && curMatches.empty())
257 matches.pop_back();
258 }
259 return true;
260 }
261
ocl_knnMatchDownload(const UMat & trainIdx,const UMat & distance,std::vector<std::vector<DMatch>> & matches,bool compactResult)262 static bool ocl_knnMatchDownload(const UMat &trainIdx, const UMat &distance, std::vector< std::vector<DMatch> > &matches, bool compactResult)
263 {
264 if (trainIdx.empty() || distance.empty())
265 return false;
266
267 Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);
268 Mat distanceCPU = distance.getMat(ACCESS_READ);
269
270 return ocl_knnMatchConvert(trainIdxCPU, distanceCPU, matches, compactResult);
271 }
272
ocl_radiusMatchSingle(InputArray query,InputArray train,UMat & trainIdx,UMat & distance,UMat & nMatches,float maxDistance,int distType)273 static bool ocl_radiusMatchSingle(InputArray query, InputArray train,
274 UMat &trainIdx, UMat &distance, UMat &nMatches, float maxDistance, int distType)
275 {
276 if (query.empty() || train.empty())
277 return false;
278
279 const int query_rows = query.rows();
280 const int train_rows = train.rows();
281
282 ensureSizeIsEnough(1, query_rows, CV_32SC1, nMatches);
283
284 if (trainIdx.empty())
285 {
286 ensureSizeIsEnough(query_rows, std::max((train_rows / 100), 10), CV_32SC1, trainIdx);
287 ensureSizeIsEnough(query_rows, std::max((train_rows / 100), 10), CV_32FC1, distance);
288 }
289
290 nMatches.setTo(Scalar::all(0));
291
292 ocl::Device devDef = ocl::Device::getDefault();
293 UMat uquery = query.getUMat(), utrain = train.getUMat();
294 int kercn = 1;
295 if (devDef.isIntel() &&
296 (0 == (uquery.step % 4)) && (0 == (uquery.cols % 4)) && (0 == (uquery.offset % 4)) &&
297 (0 == (utrain.step % 4)) && (0 == (utrain.cols % 4)) && (0 == (utrain.offset % 4)))
298 kercn = 4;
299
300 int block_size = 16;
301 int depth = query.depth();
302 cv::String opts;
303 opts = cv::format("-D T=%s -D TN=%s -D kercn=%d %s -D DIST_TYPE=%d -D BLOCK_SIZE=%d",
304 ocl::typeToStr(depth), ocl::typeToStr(CV_MAKETYPE(depth, kercn)), kercn, depth == CV_32F ? "-D T_FLOAT" : "", distType, block_size);
305 ocl::Kernel k("BruteForceMatch_RadiusMatch", ocl::features2d::brute_force_match_oclsrc, opts);
306 if (k.empty())
307 return false;
308
309 size_t globalSize[] = {(train_rows + block_size - 1) / block_size * block_size, (query_rows + block_size - 1) / block_size * block_size};
310 size_t localSize[] = {block_size, block_size};
311
312 int idx = 0;
313 idx = k.set(idx, ocl::KernelArg::PtrReadOnly(uquery));
314 idx = k.set(idx, ocl::KernelArg::PtrReadOnly(utrain));
315 idx = k.set(idx, maxDistance);
316 idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(trainIdx));
317 idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(distance));
318 idx = k.set(idx, ocl::KernelArg::PtrWriteOnly(nMatches));
319 idx = k.set(idx, uquery.rows);
320 idx = k.set(idx, uquery.cols);
321 idx = k.set(idx, utrain.rows);
322 idx = k.set(idx, utrain.cols);
323 idx = k.set(idx, trainIdx.cols);
324 idx = k.set(idx, (int)(uquery.step / sizeof(float)));
325 idx = k.set(idx, (int)(trainIdx.step / sizeof(int)));
326
327 return k.run(2, globalSize, localSize, false);
328 }
329
ocl_radiusMatchConvert(const Mat & trainIdx,const Mat & distance,const Mat & _nMatches,std::vector<std::vector<DMatch>> & matches,bool compactResult)330 static bool ocl_radiusMatchConvert(const Mat &trainIdx, const Mat &distance, const Mat &_nMatches,
331 std::vector< std::vector<DMatch> > &matches, bool compactResult)
332 {
333 if (trainIdx.empty() || distance.empty() || _nMatches.empty())
334 return false;
335
336 if( (trainIdx.type() != CV_32SC1) ||
337 (distance.type() != CV_32FC1 || distance.size() != trainIdx.size()) ||
338 (_nMatches.type() != CV_32SC1 || _nMatches.cols != trainIdx.rows) )
339 return false;
340
341 const int nQuery = trainIdx.rows;
342
343 matches.clear();
344 matches.reserve(nQuery);
345
346 const int *nMatches_ptr = _nMatches.ptr<int>();
347
348 for (int queryIdx = 0; queryIdx < nQuery; ++queryIdx)
349 {
350 const int *trainIdx_ptr = trainIdx.ptr<int>(queryIdx);
351 const float *distance_ptr = distance.ptr<float>(queryIdx);
352
353 const int nMatches = std::min(nMatches_ptr[queryIdx], trainIdx.cols);
354
355 if (nMatches == 0)
356 {
357 if (!compactResult)
358 matches.push_back(std::vector<DMatch>());
359 continue;
360 }
361
362 matches.push_back(std::vector<DMatch>(nMatches));
363 std::vector<DMatch> &curMatches = matches.back();
364
365 for (int i = 0; i < nMatches; ++i, ++trainIdx_ptr, ++distance_ptr)
366 {
367 int trainIndex = *trainIdx_ptr;
368
369 float dst = *distance_ptr;
370
371 DMatch m(queryIdx, trainIndex, 0, dst);
372
373 curMatches[i] = m;
374 }
375
376 std::sort(curMatches.begin(), curMatches.end());
377 }
378 return true;
379 }
380
ocl_radiusMatchDownload(const UMat & trainIdx,const UMat & distance,const UMat & nMatches,std::vector<std::vector<DMatch>> & matches,bool compactResult)381 static bool ocl_radiusMatchDownload(const UMat &trainIdx, const UMat &distance, const UMat &nMatches,
382 std::vector< std::vector<DMatch> > &matches, bool compactResult)
383 {
384 if (trainIdx.empty() || distance.empty() || nMatches.empty())
385 return false;
386
387 Mat trainIdxCPU = trainIdx.getMat(ACCESS_READ);
388 Mat distanceCPU = distance.getMat(ACCESS_READ);
389 Mat nMatchesCPU = nMatches.getMat(ACCESS_READ);
390
391 return ocl_radiusMatchConvert(trainIdxCPU, distanceCPU, nMatchesCPU, matches, compactResult);
392 }
393
394 /****************************************************************************************\
395 * DescriptorMatcher *
396 \****************************************************************************************/
DescriptorCollection()397 DescriptorMatcher::DescriptorCollection::DescriptorCollection()
398 {}
399
DescriptorCollection(const DescriptorCollection & collection)400 DescriptorMatcher::DescriptorCollection::DescriptorCollection( const DescriptorCollection& collection )
401 {
402 mergedDescriptors = collection.mergedDescriptors.clone();
403 std::copy( collection.startIdxs.begin(), collection.startIdxs.begin(), startIdxs.begin() );
404 }
405
~DescriptorCollection()406 DescriptorMatcher::DescriptorCollection::~DescriptorCollection()
407 {}
408
set(const std::vector<Mat> & descriptors)409 void DescriptorMatcher::DescriptorCollection::set( const std::vector<Mat>& descriptors )
410 {
411 clear();
412
413 size_t imageCount = descriptors.size();
414 CV_Assert( imageCount > 0 );
415
416 startIdxs.resize( imageCount );
417
418 int dim = -1;
419 int type = -1;
420 startIdxs[0] = 0;
421 for( size_t i = 1; i < imageCount; i++ )
422 {
423 int s = 0;
424 if( !descriptors[i-1].empty() )
425 {
426 dim = descriptors[i-1].cols;
427 type = descriptors[i-1].type();
428 s = descriptors[i-1].rows;
429 }
430 startIdxs[i] = startIdxs[i-1] + s;
431 }
432 if( imageCount == 1 )
433 {
434 if( descriptors[0].empty() ) return;
435
436 dim = descriptors[0].cols;
437 type = descriptors[0].type();
438 }
439 CV_Assert( dim > 0 );
440
441 int count = startIdxs[imageCount-1] + descriptors[imageCount-1].rows;
442
443 if( count > 0 )
444 {
445 mergedDescriptors.create( count, dim, type );
446 for( size_t i = 0; i < imageCount; i++ )
447 {
448 if( !descriptors[i].empty() )
449 {
450 CV_Assert( descriptors[i].cols == dim && descriptors[i].type() == type );
451 Mat m = mergedDescriptors.rowRange( startIdxs[i], startIdxs[i] + descriptors[i].rows );
452 descriptors[i].copyTo(m);
453 }
454 }
455 }
456 }
457
clear()458 void DescriptorMatcher::DescriptorCollection::clear()
459 {
460 startIdxs.clear();
461 mergedDescriptors.release();
462 }
463
getDescriptor(int imgIdx,int localDescIdx) const464 const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int imgIdx, int localDescIdx ) const
465 {
466 CV_Assert( imgIdx < (int)startIdxs.size() );
467 int globalIdx = startIdxs[imgIdx] + localDescIdx;
468 CV_Assert( globalIdx < (int)size() );
469
470 return getDescriptor( globalIdx );
471 }
472
getDescriptors() const473 const Mat& DescriptorMatcher::DescriptorCollection::getDescriptors() const
474 {
475 return mergedDescriptors;
476 }
477
getDescriptor(int globalDescIdx) const478 const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int globalDescIdx ) const
479 {
480 CV_Assert( globalDescIdx < size() );
481 return mergedDescriptors.row( globalDescIdx );
482 }
483
getLocalIdx(int globalDescIdx,int & imgIdx,int & localDescIdx) const484 void DescriptorMatcher::DescriptorCollection::getLocalIdx( int globalDescIdx, int& imgIdx, int& localDescIdx ) const
485 {
486 CV_Assert( (globalDescIdx>=0) && (globalDescIdx < size()) );
487 std::vector<int>::const_iterator img_it = std::upper_bound(startIdxs.begin(), startIdxs.end(), globalDescIdx);
488 --img_it;
489 imgIdx = (int)(img_it - startIdxs.begin());
490 localDescIdx = globalDescIdx - (*img_it);
491 }
492
size() const493 int DescriptorMatcher::DescriptorCollection::size() const
494 {
495 return mergedDescriptors.rows;
496 }
497
498 /*
499 * DescriptorMatcher
500 */
convertMatches(const std::vector<std::vector<DMatch>> & knnMatches,std::vector<DMatch> & matches)501 static void convertMatches( const std::vector<std::vector<DMatch> >& knnMatches, std::vector<DMatch>& matches )
502 {
503 matches.clear();
504 matches.reserve( knnMatches.size() );
505 for( size_t i = 0; i < knnMatches.size(); i++ )
506 {
507 CV_Assert( knnMatches[i].size() <= 1 );
508 if( !knnMatches[i].empty() )
509 matches.push_back( knnMatches[i][0] );
510 }
511 }
512
~DescriptorMatcher()513 DescriptorMatcher::~DescriptorMatcher()
514 {}
515
add(InputArrayOfArrays _descriptors)516 void DescriptorMatcher::add( InputArrayOfArrays _descriptors )
517 {
518 if(_descriptors.isUMatVector())
519 {
520 std::vector<UMat> descriptors;
521 _descriptors.getUMatVector(descriptors);
522 utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );
523 }
524 else if(_descriptors.isUMat())
525 {
526 std::vector<UMat> descriptors = std::vector<UMat>(1, _descriptors.getUMat());
527 utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );
528 }
529 else if(_descriptors.isMatVector())
530 {
531 std::vector<Mat> descriptors;
532 _descriptors.getMatVector(descriptors);
533 trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );
534 }
535 else if(_descriptors.isMat())
536 {
537 std::vector<Mat> descriptors = std::vector<Mat>(1, _descriptors.getMat());
538 trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );
539 }
540 else
541 CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() );
542 }
543
getTrainDescriptors() const544 const std::vector<Mat>& DescriptorMatcher::getTrainDescriptors() const
545 {
546 return trainDescCollection;
547 }
548
clear()549 void DescriptorMatcher::clear()
550 {
551 utrainDescCollection.clear();
552 trainDescCollection.clear();
553 }
554
empty() const555 bool DescriptorMatcher::empty() const
556 {
557 return trainDescCollection.empty() && utrainDescCollection.empty();
558 }
559
train()560 void DescriptorMatcher::train()
561 {}
562
match(InputArray queryDescriptors,InputArray trainDescriptors,std::vector<DMatch> & matches,InputArray mask) const563 void DescriptorMatcher::match( InputArray queryDescriptors, InputArray trainDescriptors,
564 std::vector<DMatch>& matches, InputArray mask ) const
565 {
566 Ptr<DescriptorMatcher> tempMatcher = clone(true);
567 tempMatcher->add(trainDescriptors);
568 tempMatcher->match( queryDescriptors, matches, std::vector<Mat>(1, mask.getMat()) );
569 }
570
knnMatch(InputArray queryDescriptors,InputArray trainDescriptors,std::vector<std::vector<DMatch>> & matches,int knn,InputArray mask,bool compactResult) const571 void DescriptorMatcher::knnMatch( InputArray queryDescriptors, InputArray trainDescriptors,
572 std::vector<std::vector<DMatch> >& matches, int knn,
573 InputArray mask, bool compactResult ) const
574 {
575 Ptr<DescriptorMatcher> tempMatcher = clone(true);
576 tempMatcher->add(trainDescriptors);
577 tempMatcher->knnMatch( queryDescriptors, matches, knn, std::vector<Mat>(1, mask.getMat()), compactResult );
578 }
579
radiusMatch(InputArray queryDescriptors,InputArray trainDescriptors,std::vector<std::vector<DMatch>> & matches,float maxDistance,InputArray mask,bool compactResult) const580 void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors,
581 std::vector<std::vector<DMatch> >& matches, float maxDistance, InputArray mask,
582 bool compactResult ) const
583 {
584 Ptr<DescriptorMatcher> tempMatcher = clone(true);
585 tempMatcher->add(trainDescriptors);
586 tempMatcher->radiusMatch( queryDescriptors, matches, maxDistance, std::vector<Mat>(1, mask.getMat()), compactResult );
587 }
588
match(InputArray queryDescriptors,std::vector<DMatch> & matches,InputArrayOfArrays masks)589 void DescriptorMatcher::match( InputArray queryDescriptors, std::vector<DMatch>& matches, InputArrayOfArrays masks )
590 {
591 std::vector<std::vector<DMatch> > knnMatches;
592 knnMatch( queryDescriptors, knnMatches, 1, masks, true /*compactResult*/ );
593 convertMatches( knnMatches, matches );
594 }
595
checkMasks(InputArrayOfArrays _masks,int queryDescriptorsCount) const596 void DescriptorMatcher::checkMasks( InputArrayOfArrays _masks, int queryDescriptorsCount ) const
597 {
598 std::vector<Mat> masks;
599 _masks.getMatVector(masks);
600
601 if( isMaskSupported() && !masks.empty() )
602 {
603 // Check masks
604 size_t imageCount = std::max(trainDescCollection.size(), utrainDescCollection.size() );
605 CV_Assert( masks.size() == imageCount );
606 for( size_t i = 0; i < imageCount; i++ )
607 {
608 if( !masks[i].empty() && (!trainDescCollection[i].empty() || !utrainDescCollection[i].empty() ) )
609 {
610 int rows = trainDescCollection[i].empty() ? utrainDescCollection[i].rows : trainDescCollection[i].rows;
611 CV_Assert( masks[i].rows == queryDescriptorsCount &&
612 (masks[i].cols == rows || masks[i].cols == rows) &&
613 masks[i].type() == CV_8UC1 );
614 }
615 }
616 }
617 }
618
knnMatch(InputArray queryDescriptors,std::vector<std::vector<DMatch>> & matches,int knn,InputArrayOfArrays masks,bool compactResult)619 void DescriptorMatcher::knnMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
620 InputArrayOfArrays masks, bool compactResult )
621 {
622 if( empty() || queryDescriptors.empty() )
623 return;
624
625 CV_Assert( knn > 0 );
626
627 checkMasks( masks, queryDescriptors.size().height );
628
629 train();
630 knnMatchImpl( queryDescriptors, matches, knn, masks, compactResult );
631 }
632
radiusMatch(InputArray queryDescriptors,std::vector<std::vector<DMatch>> & matches,float maxDistance,InputArrayOfArrays masks,bool compactResult)633 void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
634 InputArrayOfArrays masks, bool compactResult )
635 {
636 matches.clear();
637 if( empty() || queryDescriptors.empty() )
638 return;
639
640 CV_Assert( maxDistance > std::numeric_limits<float>::epsilon() );
641
642 checkMasks( masks, queryDescriptors.size().height );
643
644 train();
645 radiusMatchImpl( queryDescriptors, matches, maxDistance, masks, compactResult );
646 }
647
read(const FileNode &)648 void DescriptorMatcher::read( const FileNode& )
649 {}
650
write(FileStorage &) const651 void DescriptorMatcher::write( FileStorage& ) const
652 {}
653
isPossibleMatch(InputArray _mask,int queryIdx,int trainIdx)654 bool DescriptorMatcher::isPossibleMatch( InputArray _mask, int queryIdx, int trainIdx )
655 {
656 Mat mask = _mask.getMat();
657 return mask.empty() || mask.at<uchar>(queryIdx, trainIdx);
658 }
659
isMaskedOut(InputArrayOfArrays _masks,int queryIdx)660 bool DescriptorMatcher::isMaskedOut( InputArrayOfArrays _masks, int queryIdx )
661 {
662 std::vector<Mat> masks;
663 _masks.getMatVector(masks);
664
665 size_t outCount = 0;
666 for( size_t i = 0; i < masks.size(); i++ )
667 {
668 if( !masks[i].empty() && (countNonZero(masks[i].row(queryIdx)) == 0) )
669 outCount++;
670 }
671
672 return !masks.empty() && outCount == masks.size() ;
673 }
674
675
676 ////////////////////////////////////////////////////// BruteForceMatcher /////////////////////////////////////////////////
677
BFMatcher(int _normType,bool _crossCheck)678 BFMatcher::BFMatcher( int _normType, bool _crossCheck )
679 {
680 normType = _normType;
681 crossCheck = _crossCheck;
682 }
683
clone(bool emptyTrainData) const684 Ptr<DescriptorMatcher> BFMatcher::clone( bool emptyTrainData ) const
685 {
686 Ptr<BFMatcher> matcher = makePtr<BFMatcher>(normType, crossCheck);
687 if( !emptyTrainData )
688 {
689 matcher->trainDescCollection.resize(trainDescCollection.size());
690 std::transform( trainDescCollection.begin(), trainDescCollection.end(),
691 matcher->trainDescCollection.begin(), clone_op );
692 }
693 return matcher;
694 }
695
ocl_match(InputArray query,InputArray _train,std::vector<std::vector<DMatch>> & matches,int dstType)696 static bool ocl_match(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches, int dstType)
697 {
698 UMat trainIdx, distance;
699 if (!ocl_matchSingle(query, _train, trainIdx, distance, dstType))
700 return false;
701 if (!ocl_matchDownload(trainIdx, distance, matches))
702 return false;
703 return true;
704 }
705
ocl_knnMatch(InputArray query,InputArray _train,std::vector<std::vector<DMatch>> & matches,int k,int dstType,bool compactResult)706 static bool ocl_knnMatch(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches, int k, int dstType, bool compactResult)
707 {
708 UMat trainIdx, distance;
709 if (k != 2)
710 return false;
711 if (!ocl_knnMatchSingle(query, _train, trainIdx, distance, dstType))
712 return false;
713 if (!ocl_knnMatchDownload(trainIdx, distance, matches, compactResult) )
714 return false;
715 return true;
716 }
717
knnMatchImpl(InputArray _queryDescriptors,std::vector<std::vector<DMatch>> & matches,int knn,InputArrayOfArrays _masks,bool compactResult)718 void BFMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
719 InputArrayOfArrays _masks, bool compactResult )
720 {
721 int trainDescType = trainDescCollection.empty() ? utrainDescCollection[0].type() : trainDescCollection[0].type();
722 CV_Assert( _queryDescriptors.type() == trainDescType );
723
724 const int IMGIDX_SHIFT = 18;
725 const int IMGIDX_ONE = (1 << IMGIDX_SHIFT);
726
727 if( _queryDescriptors.empty() || (trainDescCollection.empty() && utrainDescCollection.empty()))
728 {
729 matches.clear();
730 return;
731 }
732
733 std::vector<Mat> masks;
734 _masks.getMatVector(masks);
735
736 if(!trainDescCollection.empty() && !utrainDescCollection.empty())
737 {
738 for(int i = 0; i < (int)utrainDescCollection.size(); i++)
739 {
740 Mat tempMat;
741 utrainDescCollection[i].copyTo(tempMat);
742 trainDescCollection.push_back(tempMat);
743 }
744 utrainDescCollection.clear();
745 }
746
747 int trainDescVectorSize = trainDescCollection.empty() ? (int)utrainDescCollection.size() : (int)trainDescCollection.size();
748 Size trainDescSize = trainDescCollection.empty() ? utrainDescCollection[0].size() : trainDescCollection[0].size();
749 int trainDescOffset = trainDescCollection.empty() ? (int)utrainDescCollection[0].offset : 0;
750
751 if ( ocl::useOpenCL() && _queryDescriptors.isUMat() && _queryDescriptors.dims()<=2 && trainDescVectorSize == 1 &&
752 _queryDescriptors.type() == CV_32FC1 && _queryDescriptors.offset() == 0 && trainDescOffset == 0 &&
753 trainDescSize.width == _queryDescriptors.size().width && masks.size() == 1 && masks[0].total() == 0 )
754 {
755 if(knn == 1)
756 {
757 if(trainDescCollection.empty())
758 {
759 if(ocl_match(_queryDescriptors, utrainDescCollection[0], matches, normType))
760 {
761 CV_IMPL_ADD(CV_IMPL_OCL);
762 return;
763 }
764 }
765 else
766 {
767 if(ocl_match(_queryDescriptors, trainDescCollection[0], matches, normType))
768 {
769 CV_IMPL_ADD(CV_IMPL_OCL);
770 return;
771 }
772 }
773 }
774 else
775 {
776 if(trainDescCollection.empty())
777 {
778 if(ocl_knnMatch(_queryDescriptors, utrainDescCollection[0], matches, knn, normType, compactResult) )
779 {
780 CV_IMPL_ADD(CV_IMPL_OCL);
781 return;
782 }
783 }
784 else
785 {
786 if(ocl_knnMatch(_queryDescriptors, trainDescCollection[0], matches, knn, normType, compactResult) )
787 {
788 CV_IMPL_ADD(CV_IMPL_OCL);
789 return;
790 }
791 }
792 }
793 }
794
795 Mat queryDescriptors = _queryDescriptors.getMat();
796 if(trainDescCollection.empty() && !utrainDescCollection.empty())
797 {
798 for(int i = 0; i < (int)utrainDescCollection.size(); i++)
799 {
800 Mat tempMat;
801 utrainDescCollection[i].copyTo(tempMat);
802 trainDescCollection.push_back(tempMat);
803 }
804 utrainDescCollection.clear();
805 }
806
807 matches.reserve(queryDescriptors.rows);
808
809 Mat dist, nidx;
810
811 int iIdx, imgCount = (int)trainDescCollection.size(), update = 0;
812 int dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ||
813 (normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;
814
815 CV_Assert( (int64)imgCount*IMGIDX_ONE < INT_MAX );
816
817 for( iIdx = 0; iIdx < imgCount; iIdx++ )
818 {
819 CV_Assert( trainDescCollection[iIdx].rows < IMGIDX_ONE );
820 batchDistance(queryDescriptors, trainDescCollection[iIdx], dist, dtype, nidx,
821 normType, knn, masks.empty() ? Mat() : masks[iIdx], update, crossCheck);
822 update += IMGIDX_ONE;
823 }
824
825 if( dtype == CV_32S )
826 {
827 Mat temp;
828 dist.convertTo(temp, CV_32F);
829 dist = temp;
830 }
831
832 for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
833 {
834 const float* distptr = dist.ptr<float>(qIdx);
835 const int* nidxptr = nidx.ptr<int>(qIdx);
836
837 matches.push_back( std::vector<DMatch>() );
838 std::vector<DMatch>& mq = matches.back();
839 mq.reserve(knn);
840
841 for( int k = 0; k < nidx.cols; k++ )
842 {
843 if( nidxptr[k] < 0 )
844 break;
845 mq.push_back( DMatch(qIdx, nidxptr[k] & (IMGIDX_ONE - 1),
846 nidxptr[k] >> IMGIDX_SHIFT, distptr[k]) );
847 }
848
849 if( mq.empty() && compactResult )
850 matches.pop_back();
851 }
852 }
853
ocl_radiusMatch(InputArray query,InputArray _train,std::vector<std::vector<DMatch>> & matches,float maxDistance,int dstType,bool compactResult)854 static bool ocl_radiusMatch(InputArray query, InputArray _train, std::vector< std::vector<DMatch> > &matches,
855 float maxDistance, int dstType, bool compactResult)
856 {
857 UMat trainIdx, distance, nMatches;
858 if (!ocl_radiusMatchSingle(query, _train, trainIdx, distance, nMatches, maxDistance, dstType))
859 return false;
860 if (!ocl_radiusMatchDownload(trainIdx, distance, nMatches, matches, compactResult))
861 return false;
862 return true;
863 }
864
radiusMatchImpl(InputArray _queryDescriptors,std::vector<std::vector<DMatch>> & matches,float maxDistance,InputArrayOfArrays _masks,bool compactResult)865 void BFMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches,
866 float maxDistance, InputArrayOfArrays _masks, bool compactResult )
867 {
868 int trainDescType = trainDescCollection.empty() ? utrainDescCollection[0].type() : trainDescCollection[0].type();
869 CV_Assert( _queryDescriptors.type() == trainDescType );
870
871 if( _queryDescriptors.empty() || (trainDescCollection.empty() && utrainDescCollection.empty()))
872 {
873 matches.clear();
874 return;
875 }
876
877 std::vector<Mat> masks;
878 _masks.getMatVector(masks);
879
880 if(!trainDescCollection.empty() && !utrainDescCollection.empty())
881 {
882 for(int i = 0; i < (int)utrainDescCollection.size(); i++)
883 {
884 Mat tempMat;
885 utrainDescCollection[i].copyTo(tempMat);
886 trainDescCollection.push_back(tempMat);
887 }
888 utrainDescCollection.clear();
889 }
890
891 int trainDescVectorSize = trainDescCollection.empty() ? (int)utrainDescCollection.size() : (int)trainDescCollection.size();
892 Size trainDescSize = trainDescCollection.empty() ? utrainDescCollection[0].size() : trainDescCollection[0].size();
893 int trainDescOffset = trainDescCollection.empty() ? (int)utrainDescCollection[0].offset : 0;
894
895 if ( ocl::useOpenCL() && _queryDescriptors.isUMat() && _queryDescriptors.dims()<=2 && trainDescVectorSize == 1 &&
896 _queryDescriptors.type() == CV_32FC1 && _queryDescriptors.offset() == 0 && trainDescOffset == 0 &&
897 trainDescSize.width == _queryDescriptors.size().width && masks.size() == 1 && masks[0].total() == 0 )
898 {
899 if (trainDescCollection.empty())
900 {
901 if(ocl_radiusMatch(_queryDescriptors, utrainDescCollection[0], matches, maxDistance, normType, compactResult) )
902 {
903 CV_IMPL_ADD(CV_IMPL_OCL);
904 return;
905 }
906 }
907 else
908 {
909 if (ocl_radiusMatch(_queryDescriptors, trainDescCollection[0], matches, maxDistance, normType, compactResult) )
910 {
911 CV_IMPL_ADD(CV_IMPL_OCL);
912 return;
913 }
914 }
915 }
916
917 Mat queryDescriptors = _queryDescriptors.getMat();
918 if(trainDescCollection.empty() && !utrainDescCollection.empty())
919 {
920 for(int i = 0; i < (int)utrainDescCollection.size(); i++)
921 {
922 Mat tempMat;
923 utrainDescCollection[i].copyTo(tempMat);
924 trainDescCollection.push_back(tempMat);
925 }
926 utrainDescCollection.clear();
927 }
928
929 matches.resize(queryDescriptors.rows);
930 Mat dist, distf;
931
932 int iIdx, imgCount = (int)trainDescCollection.size();
933 int dtype = normType == NORM_HAMMING ||
934 (normType == NORM_L1 && queryDescriptors.type() == CV_8U) ? CV_32S : CV_32F;
935
936 for( iIdx = 0; iIdx < imgCount; iIdx++ )
937 {
938 batchDistance(queryDescriptors, trainDescCollection[iIdx], dist, dtype, noArray(),
939 normType, 0, masks.empty() ? Mat() : masks[iIdx], 0, false);
940 if( dtype == CV_32S )
941 dist.convertTo(distf, CV_32F);
942 else
943 distf = dist;
944
945 for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
946 {
947 const float* distptr = distf.ptr<float>(qIdx);
948
949 std::vector<DMatch>& mq = matches[qIdx];
950 for( int k = 0; k < distf.cols; k++ )
951 {
952 if( distptr[k] <= maxDistance )
953 mq.push_back( DMatch(qIdx, k, iIdx, distptr[k]) );
954 }
955 }
956 }
957
958 int qIdx0 = 0;
959 for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
960 {
961 if( matches[qIdx].empty() && compactResult )
962 continue;
963
964 if( qIdx0 < qIdx )
965 std::swap(matches[qIdx], matches[qIdx0]);
966
967 std::sort( matches[qIdx0].begin(), matches[qIdx0].end() );
968 qIdx0++;
969 }
970 }
971
972 ///////////////////////////////////////////////////////////////////////////////////////////////////////
973
974 /*
975 * Factory function for DescriptorMatcher creating
976 */
create(const String & descriptorMatcherType)977 Ptr<DescriptorMatcher> DescriptorMatcher::create( const String& descriptorMatcherType )
978 {
979 Ptr<DescriptorMatcher> dm;
980 if( !descriptorMatcherType.compare( "FlannBased" ) )
981 {
982 dm = makePtr<FlannBasedMatcher>();
983 }
984 else if( !descriptorMatcherType.compare( "BruteForce" ) ) // L2
985 {
986 dm = makePtr<BFMatcher>(int(NORM_L2)); // anonymous enums can't be template parameters
987 }
988 else if( !descriptorMatcherType.compare( "BruteForce-SL2" ) ) // Squared L2
989 {
990 dm = makePtr<BFMatcher>(int(NORM_L2SQR));
991 }
992 else if( !descriptorMatcherType.compare( "BruteForce-L1" ) )
993 {
994 dm = makePtr<BFMatcher>(int(NORM_L1));
995 }
996 else if( !descriptorMatcherType.compare("BruteForce-Hamming") ||
997 !descriptorMatcherType.compare("BruteForce-HammingLUT") )
998 {
999 dm = makePtr<BFMatcher>(int(NORM_HAMMING));
1000 }
1001 else if( !descriptorMatcherType.compare("BruteForce-Hamming(2)") )
1002 {
1003 dm = makePtr<BFMatcher>(int(NORM_HAMMING2));
1004 }
1005 else
1006 CV_Error( Error::StsBadArg, "Unknown matcher name" );
1007
1008 return dm;
1009 }
1010
1011
1012 /*
1013 * Flann based matcher
1014 */
FlannBasedMatcher(const Ptr<flann::IndexParams> & _indexParams,const Ptr<flann::SearchParams> & _searchParams)1015 FlannBasedMatcher::FlannBasedMatcher( const Ptr<flann::IndexParams>& _indexParams, const Ptr<flann::SearchParams>& _searchParams )
1016 : indexParams(_indexParams), searchParams(_searchParams), addedDescCount(0)
1017 {
1018 CV_Assert( _indexParams );
1019 CV_Assert( _searchParams );
1020 }
1021
add(InputArrayOfArrays _descriptors)1022 void FlannBasedMatcher::add( InputArrayOfArrays _descriptors )
1023 {
1024 DescriptorMatcher::add( _descriptors );
1025 std::vector<UMat> descriptors;
1026 _descriptors.getUMatVector(descriptors);
1027
1028 for( size_t i = 0; i < descriptors.size(); i++ )
1029 {
1030 addedDescCount += descriptors[i].rows;
1031 }
1032 }
1033
clear()1034 void FlannBasedMatcher::clear()
1035 {
1036 DescriptorMatcher::clear();
1037
1038 mergedDescriptors.clear();
1039 flannIndex.release();
1040
1041 addedDescCount = 0;
1042 }
1043
train()1044 void FlannBasedMatcher::train()
1045 {
1046 if( !flannIndex || mergedDescriptors.size() < addedDescCount )
1047 {
1048 // FIXIT: Workaround for 'utrainDescCollection' issue (PR #2142)
1049 if (!utrainDescCollection.empty())
1050 {
1051 CV_Assert(trainDescCollection.size() == 0);
1052 for (size_t i = 0; i < utrainDescCollection.size(); ++i)
1053 trainDescCollection.push_back(utrainDescCollection[i].getMat(ACCESS_READ));
1054 }
1055 mergedDescriptors.set( trainDescCollection );
1056 flannIndex = makePtr<flann::Index>( mergedDescriptors.getDescriptors(), *indexParams );
1057 }
1058 }
1059
read(const FileNode & fn)1060 void FlannBasedMatcher::read( const FileNode& fn)
1061 {
1062 if (!indexParams)
1063 indexParams = makePtr<flann::IndexParams>();
1064
1065 FileNode ip = fn["indexParams"];
1066 CV_Assert(ip.type() == FileNode::SEQ);
1067
1068 for(int i = 0; i < (int)ip.size(); ++i)
1069 {
1070 CV_Assert(ip[i].type() == FileNode::MAP);
1071 String _name = (String)ip[i]["name"];
1072 int type = (int)ip[i]["type"];
1073
1074 switch(type)
1075 {
1076 case CV_8U:
1077 case CV_8S:
1078 case CV_16U:
1079 case CV_16S:
1080 case CV_32S:
1081 indexParams->setInt(_name, (int) ip[i]["value"]);
1082 break;
1083 case CV_32F:
1084 indexParams->setFloat(_name, (float) ip[i]["value"]);
1085 break;
1086 case CV_64F:
1087 indexParams->setDouble(_name, (double) ip[i]["value"]);
1088 break;
1089 case CV_USRTYPE1:
1090 indexParams->setString(_name, (String) ip[i]["value"]);
1091 break;
1092 case CV_MAKETYPE(CV_USRTYPE1,2):
1093 indexParams->setBool(_name, (int) ip[i]["value"] != 0);
1094 break;
1095 case CV_MAKETYPE(CV_USRTYPE1,3):
1096 indexParams->setAlgorithm((int) ip[i]["value"]);
1097 break;
1098 };
1099 }
1100
1101 if (!searchParams)
1102 searchParams = makePtr<flann::SearchParams>();
1103
1104 FileNode sp = fn["searchParams"];
1105 CV_Assert(sp.type() == FileNode::SEQ);
1106
1107 for(int i = 0; i < (int)sp.size(); ++i)
1108 {
1109 CV_Assert(sp[i].type() == FileNode::MAP);
1110 String _name = (String)sp[i]["name"];
1111 int type = (int)sp[i]["type"];
1112
1113 switch(type)
1114 {
1115 case CV_8U:
1116 case CV_8S:
1117 case CV_16U:
1118 case CV_16S:
1119 case CV_32S:
1120 searchParams->setInt(_name, (int) sp[i]["value"]);
1121 break;
1122 case CV_32F:
1123 searchParams->setFloat(_name, (float) ip[i]["value"]);
1124 break;
1125 case CV_64F:
1126 searchParams->setDouble(_name, (double) ip[i]["value"]);
1127 break;
1128 case CV_USRTYPE1:
1129 searchParams->setString(_name, (String) ip[i]["value"]);
1130 break;
1131 case CV_MAKETYPE(CV_USRTYPE1,2):
1132 searchParams->setBool(_name, (int) ip[i]["value"] != 0);
1133 break;
1134 case CV_MAKETYPE(CV_USRTYPE1,3):
1135 searchParams->setAlgorithm((int) ip[i]["value"]);
1136 break;
1137 };
1138 }
1139
1140 flannIndex.release();
1141 }
1142
write(FileStorage & fs) const1143 void FlannBasedMatcher::write( FileStorage& fs) const
1144 {
1145 fs << "indexParams" << "[";
1146
1147 if (indexParams)
1148 {
1149 std::vector<String> names;
1150 std::vector<int> types;
1151 std::vector<String> strValues;
1152 std::vector<double> numValues;
1153
1154 indexParams->getAll(names, types, strValues, numValues);
1155
1156 for(size_t i = 0; i < names.size(); ++i)
1157 {
1158 fs << "{" << "name" << names[i] << "type" << types[i] << "value";
1159 switch(types[i])
1160 {
1161 case CV_8U:
1162 fs << (uchar)numValues[i];
1163 break;
1164 case CV_8S:
1165 fs << (char)numValues[i];
1166 break;
1167 case CV_16U:
1168 fs << (ushort)numValues[i];
1169 break;
1170 case CV_16S:
1171 fs << (short)numValues[i];
1172 break;
1173 case CV_32S:
1174 case CV_MAKETYPE(CV_USRTYPE1,2):
1175 case CV_MAKETYPE(CV_USRTYPE1,3):
1176 fs << (int)numValues[i];
1177 break;
1178 case CV_32F:
1179 fs << (float)numValues[i];
1180 break;
1181 case CV_64F:
1182 fs << (double)numValues[i];
1183 break;
1184 case CV_USRTYPE1:
1185 fs << strValues[i];
1186 break;
1187 default:
1188 fs << (double)numValues[i];
1189 fs << "typename" << strValues[i];
1190 break;
1191 }
1192 fs << "}";
1193 }
1194 }
1195
1196 fs << "]" << "searchParams" << "[";
1197
1198 if (searchParams)
1199 {
1200 std::vector<String> names;
1201 std::vector<int> types;
1202 std::vector<String> strValues;
1203 std::vector<double> numValues;
1204
1205 searchParams->getAll(names, types, strValues, numValues);
1206
1207 for(size_t i = 0; i < names.size(); ++i)
1208 {
1209 fs << "{" << "name" << names[i] << "type" << types[i] << "value";
1210 switch(types[i])
1211 {
1212 case CV_8U:
1213 fs << (uchar)numValues[i];
1214 break;
1215 case CV_8S:
1216 fs << (char)numValues[i];
1217 break;
1218 case CV_16U:
1219 fs << (ushort)numValues[i];
1220 break;
1221 case CV_16S:
1222 fs << (short)numValues[i];
1223 break;
1224 case CV_32S:
1225 case CV_MAKETYPE(CV_USRTYPE1,2):
1226 case CV_MAKETYPE(CV_USRTYPE1,3):
1227 fs << (int)numValues[i];
1228 break;
1229 case CV_32F:
1230 fs << (float)numValues[i];
1231 break;
1232 case CV_64F:
1233 fs << (double)numValues[i];
1234 break;
1235 case CV_USRTYPE1:
1236 fs << strValues[i];
1237 break;
1238 default:
1239 fs << (double)numValues[i];
1240 fs << "typename" << strValues[i];
1241 break;
1242 }
1243 fs << "}";
1244 }
1245 }
1246 fs << "]";
1247 }
1248
isMaskSupported() const1249 bool FlannBasedMatcher::isMaskSupported() const
1250 {
1251 return false;
1252 }
1253
clone(bool emptyTrainData) const1254 Ptr<DescriptorMatcher> FlannBasedMatcher::clone( bool emptyTrainData ) const
1255 {
1256 Ptr<FlannBasedMatcher> matcher = makePtr<FlannBasedMatcher>(indexParams, searchParams);
1257 if( !emptyTrainData )
1258 {
1259 CV_Error( Error::StsNotImplemented, "deep clone functionality is not implemented, because "
1260 "Flann::Index has not copy constructor or clone method ");
1261 //matcher->flannIndex;
1262 matcher->addedDescCount = addedDescCount;
1263 matcher->mergedDescriptors = DescriptorCollection( mergedDescriptors );
1264 std::transform( trainDescCollection.begin(), trainDescCollection.end(),
1265 matcher->trainDescCollection.begin(), clone_op );
1266 }
1267 return matcher;
1268 }
1269
convertToDMatches(const DescriptorCollection & collection,const Mat & indices,const Mat & dists,std::vector<std::vector<DMatch>> & matches)1270 void FlannBasedMatcher::convertToDMatches( const DescriptorCollection& collection, const Mat& indices, const Mat& dists,
1271 std::vector<std::vector<DMatch> >& matches )
1272 {
1273 matches.resize( indices.rows );
1274 for( int i = 0; i < indices.rows; i++ )
1275 {
1276 for( int j = 0; j < indices.cols; j++ )
1277 {
1278 int idx = indices.at<int>(i, j);
1279 if( idx >= 0 )
1280 {
1281 int imgIdx, trainIdx;
1282 collection.getLocalIdx( idx, imgIdx, trainIdx );
1283 float dist = 0;
1284 if (dists.type() == CV_32S)
1285 dist = static_cast<float>( dists.at<int>(i,j) );
1286 else
1287 dist = std::sqrt(dists.at<float>(i,j));
1288 matches[i].push_back( DMatch( i, trainIdx, imgIdx, dist ) );
1289 }
1290 }
1291 }
1292 }
1293
knnMatchImpl(InputArray _queryDescriptors,std::vector<std::vector<DMatch>> & matches,int knn,InputArrayOfArrays,bool)1294 void FlannBasedMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
1295 InputArrayOfArrays /*masks*/, bool /*compactResult*/ )
1296 {
1297 Mat queryDescriptors = _queryDescriptors.getMat();
1298 Mat indices( queryDescriptors.rows, knn, CV_32SC1 );
1299 Mat dists( queryDescriptors.rows, knn, CV_32FC1);
1300 flannIndex->knnSearch( queryDescriptors, indices, dists, knn, *searchParams );
1301
1302 convertToDMatches( mergedDescriptors, indices, dists, matches );
1303 }
1304
radiusMatchImpl(InputArray _queryDescriptors,std::vector<std::vector<DMatch>> & matches,float maxDistance,InputArrayOfArrays,bool)1305 void FlannBasedMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
1306 InputArrayOfArrays /*masks*/, bool /*compactResult*/ )
1307 {
1308 Mat queryDescriptors = _queryDescriptors.getMat();
1309 const int count = mergedDescriptors.size(); // TODO do count as param?
1310 Mat indices( queryDescriptors.rows, count, CV_32SC1, Scalar::all(-1) );
1311 Mat dists( queryDescriptors.rows, count, CV_32FC1, Scalar::all(-1) );
1312 for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
1313 {
1314 Mat queryDescriptorsRow = queryDescriptors.row(qIdx);
1315 Mat indicesRow = indices.row(qIdx);
1316 Mat distsRow = dists.row(qIdx);
1317 flannIndex->radiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, count, *searchParams );
1318 }
1319
1320 convertToDMatches( mergedDescriptors, indices, dists, matches );
1321 }
1322
1323 }
1324