1// This file is part of OpenCV project.
2// It is subject to the license terms in the LICENSE file found in the top-level directory
3// of this distribution and at http://opencv.org/license.html.
4//
5// Copyright (c) 2006-2010, Rob Hess <hess@eecs.oregonstate.edu>
6// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
7// Copyright (C) 2020, Intel Corporation, all rights reserved.
8
9/**********************************************************************************************\
10 Implementation of SIFT is based on the code from http://blogs.oregonstate.edu/hess/code/sift/
11 Below is the original copyright.
12 Patent US6711293 expired in March 2020.
13
14// Copyright (c) 2006-2010, Rob Hess <hess@eecs.oregonstate.edu>
15// All rights reserved.
16
17// The following patent has been issued for methods embodied in this
18// software: "Method and apparatus for identifying scale invariant features
19// in an image and use of same for locating an object in an image," David
20// G. Lowe, US Patent 6,711,293 (March 23, 2004). Provisional application
21// filed March 8, 1999. Asignee: The University of British Columbia. For
22// further details, contact David Lowe (lowe@cs.ubc.ca) or the
23// University-Industry Liaison Office of the University of British
24// Columbia.
25
26// Note that restrictions imposed by this patent (and possibly others)
27// exist independently of and may be in conflict with the freedoms granted
28// in this license, which refers to copyright of the program, not patents
29// for any methods that it implements. Both copyright and patent law must
30// be obeyed to legally use and redistribute this program and it is not the
31// purpose of this license to induce you to infringe any patents or other
32// property right claims or to contest validity of any such claims. If you
33// redistribute or use the program, then this license merely protects you
34// from committing copyright infringement. It does not protect you from
35// committing patent infringement. So, before you do anything with this
36// program, make sure that you have permission to do so not merely in terms
37// of copyright, but also in terms of patent law.
38
39// Please note that this license is not to be understood as a guarantee
40// either. If you use the program according to this license, but in
41// conflict with patent law, it does not mean that the licensor will refund
42// you for any losses that you incur if you are sued for your patent
43// infringement.
44
45// Redistribution and use in source and binary forms, with or without
46// modification, are permitted provided that the following conditions are
47// met:
48// * Redistributions of source code must retain the above copyright and
49// patent notices, this list of conditions and the following
50// disclaimer.
51// * Redistributions in binary form must reproduce the above copyright
52// notice, this list of conditions and the following disclaimer in
53// the documentation and/or other materials provided with the
54// distribution.
55// * Neither the name of Oregon State University nor the names of its
56// contributors may be used to endorse or promote products derived
57// from this software without specific prior written permission.
58
59// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
60// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
62// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
63// HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
64// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
65// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
66// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
67// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
68// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
69// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70\**********************************************************************************************/
71
72#include "precomp.hpp"
73#include <opencv2/core/hal/hal.hpp>
74#include <opencv2/core/utils/tls.hpp>
75#include <opencv2/core/utils/logger.hpp>
76
77#include "sift.simd.hpp"
78#include "sift.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content
79
80namespace cv {
81
82/*!
83 SIFT implementation.
84
85 The class implements SIFT algorithm by D. Lowe.
86 */
87class SIFT_Impl : public SIFT
88{
89public:
90 explicit SIFT_Impl( int nfeatures = 0, int nOctaveLayers = 3,
91 double contrastThreshold = 0.04, double edgeThreshold = 10,
92 double sigma = 1.6, int descriptorType = CV_32F,
93 bool enable_precise_upscale = true );
94
95 //! returns the descriptor size in floats (128)
96 int descriptorSize() const CV_OVERRIDE;
97
98 //! returns the descriptor type
99 int descriptorType() const CV_OVERRIDE;
100
101 //! returns the default norm type
102 int defaultNorm() const CV_OVERRIDE;
103
104 //! finds the keypoints and computes descriptors for them using SIFT algorithm.
105 //! Optionally it can compute descriptors for the user-provided keypoints
106 void detectAndCompute(InputArray img, InputArray mask,
107 std::vector<KeyPoint>& keypoints,
108 OutputArray descriptors,
109 bool useProvidedKeypoints = false) CV_OVERRIDE;
110
111 void buildGaussianPyramid( const Mat& base, std::vector<Mat>& pyr, int nOctaves ) const;
112 void buildDoGPyramid( const std::vector<Mat>& pyr, std::vector<Mat>& dogpyr ) const;
113 void findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const std::vector<Mat>& dog_pyr,
114 std::vector<KeyPoint>& keypoints ) const;
115
116 void read( const FileNode& fn) CV_OVERRIDE;
117 void write( FileStorage& fs) const CV_OVERRIDE;
118
119 void setNFeatures(int maxFeatures) CV_OVERRIDE { nfeatures = maxFeatures; }
120 int getNFeatures() const CV_OVERRIDE { return nfeatures; }
121
122 void setNOctaveLayers(int nOctaveLayers_) CV_OVERRIDE { nOctaveLayers = nOctaveLayers_; }
123 int getNOctaveLayers() const CV_OVERRIDE { return nOctaveLayers; }
124
125 void setContrastThreshold(double contrastThreshold_) CV_OVERRIDE { contrastThreshold = contrastThreshold_; }
126 double getContrastThreshold() const CV_OVERRIDE { return contrastThreshold; }
127
128 void setEdgeThreshold(double edgeThreshold_) CV_OVERRIDE { edgeThreshold = edgeThreshold_; }
129 double getEdgeThreshold() const CV_OVERRIDE { return edgeThreshold; }
130
131 void setSigma(double sigma_) CV_OVERRIDE { sigma = sigma_; }
132 double getSigma() const CV_OVERRIDE { return sigma; }
133
134protected:
135 CV_PROP_RW int nfeatures;
136 CV_PROP_RW int nOctaveLayers;
137 CV_PROP_RW double contrastThreshold;
138 CV_PROP_RW double edgeThreshold;
139 CV_PROP_RW double sigma;
140 CV_PROP_RW int descriptor_type;
141 CV_PROP_RW bool enable_precise_upscale;
142};
143
144Ptr<SIFT> SIFT::create( int _nfeatures, int _nOctaveLayers,
145 double _contrastThreshold, double _edgeThreshold, double _sigma, bool enable_precise_upscale )
146{
147 CV_TRACE_FUNCTION();
148
149 return makePtr<SIFT_Impl>(a1: _nfeatures, a1: _nOctaveLayers, a1: _contrastThreshold, a1: _edgeThreshold, a1: _sigma, CV_32F, a1: enable_precise_upscale);
150}
151
152Ptr<SIFT> SIFT::create( int _nfeatures, int _nOctaveLayers,
153 double _contrastThreshold, double _edgeThreshold, double _sigma, int _descriptorType, bool enable_precise_upscale )
154{
155 CV_TRACE_FUNCTION();
156
157 // SIFT descriptor supports 32bit floating point and 8bit unsigned int.
158 CV_Assert(_descriptorType == CV_32F || _descriptorType == CV_8U);
159 return makePtr<SIFT_Impl>(a1: _nfeatures, a1: _nOctaveLayers, a1: _contrastThreshold, a1: _edgeThreshold, a1: _sigma, a1: _descriptorType, a1: enable_precise_upscale);
160}
161
162String SIFT::getDefaultName() const
163{
164 return (Feature2D::getDefaultName() + ".SIFT");
165}
166
167static inline void
168unpackOctave(const KeyPoint& kpt, int& octave, int& layer, float& scale)
169{
170 octave = kpt.octave & 255;
171 layer = (kpt.octave >> 8) & 255;
172 octave = octave < 128 ? octave : (-128 | octave);
173 scale = octave >= 0 ? 1.f/(1 << octave) : (float)(1 << -octave);
174}
175
176static Mat createInitialImage( const Mat& img, bool doubleImageSize, float sigma, bool enable_precise_upscale )
177{
178 CV_TRACE_FUNCTION();
179
180 Mat gray, gray_fpt;
181 if( img.channels() == 3 || img.channels() == 4 )
182 {
183 cvtColor(src: img, dst: gray, code: COLOR_BGR2GRAY);
184 gray.convertTo(m: gray_fpt, rtype: DataType<sift_wt>::type, alpha: SIFT_FIXPT_SCALE, beta: 0);
185 }
186 else
187 img.convertTo(m: gray_fpt, rtype: DataType<sift_wt>::type, alpha: SIFT_FIXPT_SCALE, beta: 0);
188
189 float sig_diff;
190
191 if( doubleImageSize )
192 {
193 sig_diff = sqrtf( x: std::max(a: sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA * 4, b: 0.01f) );
194
195 Mat dbl;
196 if (enable_precise_upscale) {
197 dbl.create(size: Size(gray_fpt.cols*2, gray_fpt.rows*2), type: gray_fpt.type());
198 Mat H = Mat::zeros(rows: 2, cols: 3, CV_32F);
199 H.at<float>(i0: 0, i1: 0) = 0.5f;
200 H.at<float>(i0: 1, i1: 1) = 0.5f;
201
202 cv::warpAffine(src: gray_fpt, dst: dbl, M: H, dsize: dbl.size(), flags: INTER_LINEAR | WARP_INVERSE_MAP, borderMode: BORDER_REFLECT);
203 } else {
204#if DoG_TYPE_SHORT
205 resize(gray_fpt, dbl, Size(gray_fpt.cols*2, gray_fpt.rows*2), 0, 0, INTER_LINEAR_EXACT);
206#else
207 resize(src: gray_fpt, dst: dbl, dsize: Size(gray_fpt.cols*2, gray_fpt.rows*2), fx: 0, fy: 0, interpolation: INTER_LINEAR);
208#endif
209 }
210 Mat result;
211 GaussianBlur(src: dbl, dst: result, ksize: Size(), sigmaX: sig_diff, sigmaY: sig_diff);
212 return result;
213 }
214 else
215 {
216 sig_diff = sqrtf( x: std::max(a: sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA, b: 0.01f) );
217 Mat result;
218 GaussianBlur(src: gray_fpt, dst: result, ksize: Size(), sigmaX: sig_diff, sigmaY: sig_diff);
219 return result;
220 }
221}
222
223
224void SIFT_Impl::buildGaussianPyramid( const Mat& base, std::vector<Mat>& pyr, int nOctaves ) const
225{
226 CV_TRACE_FUNCTION();
227
228 std::vector<double> sig(nOctaveLayers + 3);
229 pyr.resize(new_size: nOctaves*(nOctaveLayers + 3));
230
231 // precompute Gaussian sigmas using the following formula:
232 // \sigma_{total}^2 = \sigma_{i}^2 + \sigma_{i-1}^2
233 sig[0] = sigma;
234 double k = std::pow( x: 2., y: 1. / nOctaveLayers );
235 for( int i = 1; i < nOctaveLayers + 3; i++ )
236 {
237 double sig_prev = std::pow(x: k, y: (double)(i-1))*sigma;
238 double sig_total = sig_prev*k;
239 sig[i] = std::sqrt(x: sig_total*sig_total - sig_prev*sig_prev);
240 }
241
242 for( int o = 0; o < nOctaves; o++ )
243 {
244 for( int i = 0; i < nOctaveLayers + 3; i++ )
245 {
246 Mat& dst = pyr[o*(nOctaveLayers + 3) + i];
247 if( o == 0 && i == 0 )
248 dst = base;
249 // base of new octave is halved image from end of previous octave
250 else if( i == 0 )
251 {
252 const Mat& src = pyr[(o-1)*(nOctaveLayers + 3) + nOctaveLayers];
253 resize(src, dst, dsize: Size(src.cols/2, src.rows/2),
254 fx: 0, fy: 0, interpolation: INTER_NEAREST);
255 }
256 else
257 {
258 const Mat& src = pyr[o*(nOctaveLayers + 3) + i-1];
259 GaussianBlur(src, dst, ksize: Size(), sigmaX: sig[i], sigmaY: sig[i]);
260 }
261 }
262 }
263}
264
265
266class buildDoGPyramidComputer : public ParallelLoopBody
267{
268public:
269 buildDoGPyramidComputer(
270 int _nOctaveLayers,
271 const std::vector<Mat>& _gpyr,
272 std::vector<Mat>& _dogpyr)
273 : nOctaveLayers(_nOctaveLayers),
274 gpyr(_gpyr),
275 dogpyr(_dogpyr) { }
276
277 void operator()( const cv::Range& range ) const CV_OVERRIDE
278 {
279 CV_TRACE_FUNCTION();
280
281 const int begin = range.start;
282 const int end = range.end;
283
284 for( int a = begin; a < end; a++ )
285 {
286 const int o = a / (nOctaveLayers + 2);
287 const int i = a % (nOctaveLayers + 2);
288
289 const Mat& src1 = gpyr[o*(nOctaveLayers + 3) + i];
290 const Mat& src2 = gpyr[o*(nOctaveLayers + 3) + i + 1];
291 Mat& dst = dogpyr[o*(nOctaveLayers + 2) + i];
292 subtract(src1: src2, src2: src1, dst, mask: noArray(), dtype: DataType<sift_wt>::type);
293 }
294 }
295
296private:
297 int nOctaveLayers;
298 const std::vector<Mat>& gpyr;
299 std::vector<Mat>& dogpyr;
300};
301
302void SIFT_Impl::buildDoGPyramid( const std::vector<Mat>& gpyr, std::vector<Mat>& dogpyr ) const
303{
304 CV_TRACE_FUNCTION();
305
306 int nOctaves = (int)gpyr.size()/(nOctaveLayers + 3);
307 dogpyr.resize( new_size: nOctaves*(nOctaveLayers + 2) );
308
309 parallel_for_(range: Range(0, nOctaves * (nOctaveLayers + 2)), body: buildDoGPyramidComputer(nOctaveLayers, gpyr, dogpyr));
310}
311
312class findScaleSpaceExtremaComputer : public ParallelLoopBody
313{
314public:
315 findScaleSpaceExtremaComputer(
316 int _o,
317 int _i,
318 int _threshold,
319 int _idx,
320 int _step,
321 int _cols,
322 int _nOctaveLayers,
323 double _contrastThreshold,
324 double _edgeThreshold,
325 double _sigma,
326 const std::vector<Mat>& _gauss_pyr,
327 const std::vector<Mat>& _dog_pyr,
328 TLSData<std::vector<KeyPoint> > &_tls_kpts_struct)
329
330 : o(_o),
331 i(_i),
332 threshold(_threshold),
333 idx(_idx),
334 step(_step),
335 cols(_cols),
336 nOctaveLayers(_nOctaveLayers),
337 contrastThreshold(_contrastThreshold),
338 edgeThreshold(_edgeThreshold),
339 sigma(_sigma),
340 gauss_pyr(_gauss_pyr),
341 dog_pyr(_dog_pyr),
342 tls_kpts_struct(_tls_kpts_struct) { }
343 void operator()( const cv::Range& range ) const CV_OVERRIDE
344 {
345 CV_TRACE_FUNCTION();
346
347 std::vector<KeyPoint>& kpts = tls_kpts_struct.getRef();
348
349 CV_CPU_DISPATCH(findScaleSpaceExtrema, (o, i, threshold, idx, step, cols, nOctaveLayers, contrastThreshold, edgeThreshold, sigma, gauss_pyr, dog_pyr, kpts, range),
350 CV_CPU_DISPATCH_MODES_ALL);
351 }
352private:
353 int o, i;
354 int threshold;
355 int idx, step, cols;
356 int nOctaveLayers;
357 double contrastThreshold;
358 double edgeThreshold;
359 double sigma;
360 const std::vector<Mat>& gauss_pyr;
361 const std::vector<Mat>& dog_pyr;
362 TLSData<std::vector<KeyPoint> > &tls_kpts_struct;
363};
364
365//
366// Detects features at extrema in DoG scale space. Bad features are discarded
367// based on contrast and ratio of principal curvatures.
368void SIFT_Impl::findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const std::vector<Mat>& dog_pyr,
369 std::vector<KeyPoint>& keypoints ) const
370{
371 CV_TRACE_FUNCTION();
372
373 const int nOctaves = (int)gauss_pyr.size()/(nOctaveLayers + 3);
374 const int threshold = cvFloor(value: 0.5 * contrastThreshold / nOctaveLayers * 255 * SIFT_FIXPT_SCALE);
375
376 keypoints.clear();
377 TLSDataAccumulator<std::vector<KeyPoint> > tls_kpts_struct;
378
379 for( int o = 0; o < nOctaves; o++ )
380 for( int i = 1; i <= nOctaveLayers; i++ )
381 {
382 const int idx = o*(nOctaveLayers+2)+i;
383 const Mat& img = dog_pyr[idx];
384 const int step = (int)img.step1();
385 const int rows = img.rows, cols = img.cols;
386
387 parallel_for_(range: Range(SIFT_IMG_BORDER, rows-SIFT_IMG_BORDER),
388 body: findScaleSpaceExtremaComputer(
389 o, i, threshold, idx, step, cols,
390 nOctaveLayers,
391 contrastThreshold,
392 edgeThreshold,
393 sigma,
394 gauss_pyr, dog_pyr, tls_kpts_struct));
395 }
396
397 std::vector<std::vector<KeyPoint>*> kpt_vecs;
398 tls_kpts_struct.gather(data&: kpt_vecs);
399 for (size_t i = 0; i < kpt_vecs.size(); ++i) {
400 keypoints.insert(position: keypoints.end(), first: kpt_vecs[i]->begin(), last: kpt_vecs[i]->end());
401 }
402}
403
404
405static
406void calcSIFTDescriptor(
407 const Mat& img, Point2f ptf, float ori, float scl,
408 int d, int n, Mat& dst, int row
409)
410{
411 CV_TRACE_FUNCTION();
412
413 CV_CPU_DISPATCH(calcSIFTDescriptor, (img, ptf, ori, scl, d, n, dst, row),
414 CV_CPU_DISPATCH_MODES_ALL);
415}
416
417class calcDescriptorsComputer : public ParallelLoopBody
418{
419public:
420 calcDescriptorsComputer(const std::vector<Mat>& _gpyr,
421 const std::vector<KeyPoint>& _keypoints,
422 Mat& _descriptors,
423 int _nOctaveLayers,
424 int _firstOctave)
425 : gpyr(_gpyr),
426 keypoints(_keypoints),
427 descriptors(_descriptors),
428 nOctaveLayers(_nOctaveLayers),
429 firstOctave(_firstOctave) { }
430
431 void operator()( const cv::Range& range ) const CV_OVERRIDE
432 {
433 CV_TRACE_FUNCTION();
434
435 const int begin = range.start;
436 const int end = range.end;
437
438 static const int d = SIFT_DESCR_WIDTH, n = SIFT_DESCR_HIST_BINS;
439
440 for ( int i = begin; i<end; i++ )
441 {
442 KeyPoint kpt = keypoints[i];
443 int octave, layer;
444 float scale;
445 unpackOctave(kpt, octave, layer, scale);
446 CV_Assert(octave >= firstOctave && layer <= nOctaveLayers+2);
447 float size=kpt.size*scale;
448 Point2f ptf(kpt.pt.x*scale, kpt.pt.y*scale);
449 const Mat& img = gpyr[(octave - firstOctave)*(nOctaveLayers + 3) + layer];
450
451 float angle = 360.f - kpt.angle;
452 if(std::abs(x: angle - 360.f) < FLT_EPSILON)
453 angle = 0.f;
454 calcSIFTDescriptor(img, ptf, ori: angle, scl: size*0.5f, d, n, dst&: descriptors, row: i);
455 }
456 }
457private:
458 const std::vector<Mat>& gpyr;
459 const std::vector<KeyPoint>& keypoints;
460 Mat& descriptors;
461 int nOctaveLayers;
462 int firstOctave;
463};
464
465static void calcDescriptors(const std::vector<Mat>& gpyr, const std::vector<KeyPoint>& keypoints,
466 Mat& descriptors, int nOctaveLayers, int firstOctave )
467{
468 CV_TRACE_FUNCTION();
469 parallel_for_(range: Range(0, static_cast<int>(keypoints.size())), body: calcDescriptorsComputer(gpyr, keypoints, descriptors, nOctaveLayers, firstOctave));
470}
471
472//////////////////////////////////////////////////////////////////////////////////////////
473
474SIFT_Impl::SIFT_Impl( int _nfeatures, int _nOctaveLayers,
475 double _contrastThreshold, double _edgeThreshold, double _sigma, int _descriptorType, bool _enable_precise_upscale)
476 : nfeatures(_nfeatures), nOctaveLayers(_nOctaveLayers),
477 contrastThreshold(_contrastThreshold), edgeThreshold(_edgeThreshold), sigma(_sigma), descriptor_type(_descriptorType),
478 enable_precise_upscale(_enable_precise_upscale)
479{
480 if (!enable_precise_upscale) {
481 CV_LOG_ONCE_INFO(NULL, "precise upscale disabled, this is now deprecated as it was found to induce a location bias");
482 }
483}
484
485int SIFT_Impl::descriptorSize() const
486{
487 return SIFT_DESCR_WIDTH*SIFT_DESCR_WIDTH*SIFT_DESCR_HIST_BINS;
488}
489
490int SIFT_Impl::descriptorType() const
491{
492 return descriptor_type;
493}
494
495int SIFT_Impl::defaultNorm() const
496{
497 return NORM_L2;
498}
499
500
501void SIFT_Impl::detectAndCompute(InputArray _image, InputArray _mask,
502 std::vector<KeyPoint>& keypoints,
503 OutputArray _descriptors,
504 bool useProvidedKeypoints)
505{
506 CV_TRACE_FUNCTION();
507
508 int firstOctave = -1, actualNOctaves = 0, actualNLayers = 0;
509 Mat image = _image.getMat(), mask = _mask.getMat();
510
511 if( image.empty() || image.depth() != CV_8U )
512 CV_Error( Error::StsBadArg, "image is empty or has incorrect depth (!=CV_8U)" );
513
514 if( !mask.empty() && mask.type() != CV_8UC1 )
515 CV_Error( Error::StsBadArg, "mask has incorrect type (!=CV_8UC1)" );
516
517 if( useProvidedKeypoints )
518 {
519 firstOctave = 0;
520 int maxOctave = INT_MIN;
521 for( size_t i = 0; i < keypoints.size(); i++ )
522 {
523 int octave, layer;
524 float scale;
525 unpackOctave(kpt: keypoints[i], octave, layer, scale);
526 firstOctave = std::min(a: firstOctave, b: octave);
527 maxOctave = std::max(a: maxOctave, b: octave);
528 actualNLayers = std::max(a: actualNLayers, b: layer-2);
529 }
530
531 firstOctave = std::min(a: firstOctave, b: 0);
532 CV_Assert( firstOctave >= -1 && actualNLayers <= nOctaveLayers );
533 actualNOctaves = maxOctave - firstOctave + 1;
534 }
535
536 Mat base = createInitialImage(img: image, doubleImageSize: firstOctave < 0, sigma: (float)sigma, enable_precise_upscale);
537 std::vector<Mat> gpyr;
538 int nOctaves = actualNOctaves > 0 ? actualNOctaves : cvRound(value: std::log( x: (double)std::min( a: base.cols, b: base.rows ) ) / std::log(x: 2.) - 2) - firstOctave;
539
540 //double t, tf = getTickFrequency();
541 //t = (double)getTickCount();
542 buildGaussianPyramid(base, pyr&: gpyr, nOctaves);
543
544 //t = (double)getTickCount() - t;
545 //printf("pyramid construction time: %g\n", t*1000./tf);
546
547 if( !useProvidedKeypoints )
548 {
549 std::vector<Mat> dogpyr;
550 buildDoGPyramid(gpyr, dogpyr);
551 //t = (double)getTickCount();
552 findScaleSpaceExtrema(gauss_pyr: gpyr, dog_pyr: dogpyr, keypoints);
553 KeyPointsFilter::removeDuplicatedSorted( keypoints );
554
555 if( nfeatures > 0 )
556 KeyPointsFilter::retainBest(keypoints, npoints: nfeatures);
557 //t = (double)getTickCount() - t;
558 //printf("keypoint detection time: %g\n", t*1000./tf);
559
560 if( firstOctave < 0 )
561 for( size_t i = 0; i < keypoints.size(); i++ )
562 {
563 KeyPoint& kpt = keypoints[i];
564 float scale = 1.f/(float)(1 << -firstOctave);
565 kpt.octave = (kpt.octave & ~255) | ((kpt.octave + firstOctave) & 255);
566 kpt.pt *= scale;
567 kpt.size *= scale;
568 }
569
570 if( !mask.empty() )
571 KeyPointsFilter::runByPixelsMask( keypoints, mask );
572 }
573 else
574 {
575 // filter keypoints by mask
576 //KeyPointsFilter::runByPixelsMask( keypoints, mask );
577 }
578
579 if( _descriptors.needed() )
580 {
581 //t = (double)getTickCount();
582 int dsize = descriptorSize();
583 _descriptors.create(rows: (int)keypoints.size(), cols: dsize, type: descriptor_type);
584
585 Mat descriptors = _descriptors.getMat();
586 calcDescriptors(gpyr, keypoints, descriptors, nOctaveLayers, firstOctave);
587 //t = (double)getTickCount() - t;
588 //printf("descriptor extraction time: %g\n", t*1000./tf);
589 }
590}
591
592void SIFT_Impl::read( const FileNode& fn)
593{
594 // if node is empty, keep previous value
595 if (!fn["nfeatures"].empty())
596 fn["nfeatures"] >> nfeatures;
597 if (!fn["nOctaveLayers"].empty())
598 fn["nOctaveLayers"] >> nOctaveLayers;
599 if (!fn["contrastThreshold"].empty())
600 fn["contrastThreshold"] >> contrastThreshold;
601 if (!fn["edgeThreshold"].empty())
602 fn["edgeThreshold"] >> edgeThreshold;
603 if (!fn["sigma"].empty())
604 fn["sigma"] >> sigma;
605 if (!fn["descriptorType"].empty())
606 fn["descriptorType"] >> descriptor_type;
607}
608void SIFT_Impl::write( FileStorage& fs) const
609{
610 if(fs.isOpened())
611 {
612 fs << "name" << getDefaultName();
613 fs << "nfeatures" << nfeatures;
614 fs << "nOctaveLayers" << nOctaveLayers;
615 fs << "contrastThreshold" << contrastThreshold;
616 fs << "edgeThreshold" << edgeThreshold;
617 fs << "sigma" << sigma;
618 fs << "descriptorType" << descriptor_type;
619 }
620}
621
622}
623

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of opencv/modules/features2d/src/sift.dispatch.cpp