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.
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.
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.
14 // Copyright (c) 2006-2010, Rob Hess <hess@eecs.oregonstate.edu>
15 // All rights reserved.
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
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.
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
45 // Redistribution and use in source and binary forms, with or without
46 // modification, are permitted provided that the following conditions are
48 // * Redistributions of source code must retain the above copyright and
49 // patent notices, this list of conditions and the following
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
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.
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 \**********************************************************************************************/
72 #include "precomp.hpp"
73 #include <opencv2/core/hal/hal.hpp>
74 #include <opencv2/core/utils/tls.hpp>
76 #include "sift.simd.hpp"
77 #include "sift.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content
84 The class implements SIFT algorithm by D. Lowe.
86 class SIFT_Impl : public SIFT
89 explicit SIFT_Impl( int nfeatures = 0, int nOctaveLayers = 3,
90 double contrastThreshold = 0.04, double edgeThreshold = 10,
91 double sigma = 1.6, int descriptorType = CV_32F );
93 //! returns the descriptor size in floats (128)
94 int descriptorSize() const CV_OVERRIDE;
96 //! returns the descriptor type
97 int descriptorType() const CV_OVERRIDE;
99 //! returns the default norm type
100 int defaultNorm() const CV_OVERRIDE;
102 //! finds the keypoints and computes descriptors for them using SIFT algorithm.
103 //! Optionally it can compute descriptors for the user-provided keypoints
104 void detectAndCompute(InputArray img, InputArray mask,
105 std::vector<KeyPoint>& keypoints,
106 OutputArray descriptors,
107 bool useProvidedKeypoints = false) CV_OVERRIDE;
109 void buildGaussianPyramid( const Mat& base, std::vector<Mat>& pyr, int nOctaves ) const;
110 void buildDoGPyramid( const std::vector<Mat>& pyr, std::vector<Mat>& dogpyr ) const;
111 void findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const std::vector<Mat>& dog_pyr,
112 std::vector<KeyPoint>& keypoints ) const;
115 CV_PROP_RW int nfeatures;
116 CV_PROP_RW int nOctaveLayers;
117 CV_PROP_RW double contrastThreshold;
118 CV_PROP_RW double edgeThreshold;
119 CV_PROP_RW double sigma;
120 CV_PROP_RW int descriptor_type;
123 Ptr<SIFT> SIFT::create( int _nfeatures, int _nOctaveLayers,
124 double _contrastThreshold, double _edgeThreshold, double _sigma )
128 return makePtr<SIFT_Impl>(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma, CV_32F);
131 Ptr<SIFT> SIFT::create( int _nfeatures, int _nOctaveLayers,
132 double _contrastThreshold, double _edgeThreshold, double _sigma, int _descriptorType )
136 // SIFT descriptor supports 32bit floating point and 8bit unsigned int.
137 CV_Assert(_descriptorType == CV_32F || _descriptorType == CV_8U);
138 return makePtr<SIFT_Impl>(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma, _descriptorType);
141 String SIFT::getDefaultName() const
143 return (Feature2D::getDefaultName() + ".SIFT");
147 unpackOctave(const KeyPoint& kpt, int& octave, int& layer, float& scale)
149 octave = kpt.octave & 255;
150 layer = (kpt.octave >> 8) & 255;
151 octave = octave < 128 ? octave : (-128 | octave);
152 scale = octave >= 0 ? 1.f/(1 << octave) : (float)(1 << -octave);
155 static Mat createInitialImage( const Mat& img, bool doubleImageSize, float sigma )
160 if( img.channels() == 3 || img.channels() == 4 )
162 cvtColor(img, gray, COLOR_BGR2GRAY);
163 gray.convertTo(gray_fpt, DataType<sift_wt>::type, SIFT_FIXPT_SCALE, 0);
166 img.convertTo(gray_fpt, DataType<sift_wt>::type, SIFT_FIXPT_SCALE, 0);
170 if( doubleImageSize )
172 sig_diff = sqrtf( std::max(sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA * 4, 0.01f) );
175 resize(gray_fpt, dbl, Size(gray_fpt.cols*2, gray_fpt.rows*2), 0, 0, INTER_LINEAR_EXACT);
177 resize(gray_fpt, dbl, Size(gray_fpt.cols*2, gray_fpt.rows*2), 0, 0, INTER_LINEAR);
180 GaussianBlur(dbl, result, Size(), sig_diff, sig_diff);
185 sig_diff = sqrtf( std::max(sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA, 0.01f) );
187 GaussianBlur(gray_fpt, result, Size(), sig_diff, sig_diff);
193 void SIFT_Impl::buildGaussianPyramid( const Mat& base, std::vector<Mat>& pyr, int nOctaves ) const
197 std::vector<double> sig(nOctaveLayers + 3);
198 pyr.resize(nOctaves*(nOctaveLayers + 3));
200 // precompute Gaussian sigmas using the following formula:
201 // \sigma_{total}^2 = \sigma_{i}^2 + \sigma_{i-1}^2
203 double k = std::pow( 2., 1. / nOctaveLayers );
204 for( int i = 1; i < nOctaveLayers + 3; i++ )
206 double sig_prev = std::pow(k, (double)(i-1))*sigma;
207 double sig_total = sig_prev*k;
208 sig[i] = std::sqrt(sig_total*sig_total - sig_prev*sig_prev);
211 for( int o = 0; o < nOctaves; o++ )
213 for( int i = 0; i < nOctaveLayers + 3; i++ )
215 Mat& dst = pyr[o*(nOctaveLayers + 3) + i];
216 if( o == 0 && i == 0 )
218 // base of new octave is halved image from end of previous octave
221 const Mat& src = pyr[(o-1)*(nOctaveLayers + 3) + nOctaveLayers];
222 resize(src, dst, Size(src.cols/2, src.rows/2),
223 0, 0, INTER_NEAREST);
227 const Mat& src = pyr[o*(nOctaveLayers + 3) + i-1];
228 GaussianBlur(src, dst, Size(), sig[i], sig[i]);
235 class buildDoGPyramidComputer : public ParallelLoopBody
238 buildDoGPyramidComputer(
240 const std::vector<Mat>& _gpyr,
241 std::vector<Mat>& _dogpyr)
242 : nOctaveLayers(_nOctaveLayers),
246 void operator()( const cv::Range& range ) const CV_OVERRIDE
250 const int begin = range.start;
251 const int end = range.end;
253 for( int a = begin; a < end; a++ )
255 const int o = a / (nOctaveLayers + 2);
256 const int i = a % (nOctaveLayers + 2);
258 const Mat& src1 = gpyr[o*(nOctaveLayers + 3) + i];
259 const Mat& src2 = gpyr[o*(nOctaveLayers + 3) + i + 1];
260 Mat& dst = dogpyr[o*(nOctaveLayers + 2) + i];
261 subtract(src2, src1, dst, noArray(), DataType<sift_wt>::type);
267 const std::vector<Mat>& gpyr;
268 std::vector<Mat>& dogpyr;
271 void SIFT_Impl::buildDoGPyramid( const std::vector<Mat>& gpyr, std::vector<Mat>& dogpyr ) const
275 int nOctaves = (int)gpyr.size()/(nOctaveLayers + 3);
276 dogpyr.resize( nOctaves*(nOctaveLayers + 2) );
278 parallel_for_(Range(0, nOctaves * (nOctaveLayers + 2)), buildDoGPyramidComputer(nOctaveLayers, gpyr, dogpyr));
281 class findScaleSpaceExtremaComputer : public ParallelLoopBody
284 findScaleSpaceExtremaComputer(
292 double _contrastThreshold,
293 double _edgeThreshold,
295 const std::vector<Mat>& _gauss_pyr,
296 const std::vector<Mat>& _dog_pyr,
297 TLSData<std::vector<KeyPoint> > &_tls_kpts_struct)
301 threshold(_threshold),
305 nOctaveLayers(_nOctaveLayers),
306 contrastThreshold(_contrastThreshold),
307 edgeThreshold(_edgeThreshold),
309 gauss_pyr(_gauss_pyr),
311 tls_kpts_struct(_tls_kpts_struct) { }
312 void operator()( const cv::Range& range ) const CV_OVERRIDE
316 std::vector<KeyPoint>& kpts = tls_kpts_struct.getRef();
318 CV_CPU_DISPATCH(findScaleSpaceExtrema, (o, i, threshold, idx, step, cols, nOctaveLayers, contrastThreshold, edgeThreshold, sigma, gauss_pyr, dog_pyr, kpts, range),
319 CV_CPU_DISPATCH_MODES_ALL);
326 double contrastThreshold;
327 double edgeThreshold;
329 const std::vector<Mat>& gauss_pyr;
330 const std::vector<Mat>& dog_pyr;
331 TLSData<std::vector<KeyPoint> > &tls_kpts_struct;
335 // Detects features at extrema in DoG scale space. Bad features are discarded
336 // based on contrast and ratio of principal curvatures.
337 void SIFT_Impl::findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const std::vector<Mat>& dog_pyr,
338 std::vector<KeyPoint>& keypoints ) const
342 const int nOctaves = (int)gauss_pyr.size()/(nOctaveLayers + 3);
343 const int threshold = cvFloor(0.5 * contrastThreshold / nOctaveLayers * 255 * SIFT_FIXPT_SCALE);
346 TLSDataAccumulator<std::vector<KeyPoint> > tls_kpts_struct;
348 for( int o = 0; o < nOctaves; o++ )
349 for( int i = 1; i <= nOctaveLayers; i++ )
351 const int idx = o*(nOctaveLayers+2)+i;
352 const Mat& img = dog_pyr[idx];
353 const int step = (int)img.step1();
354 const int rows = img.rows, cols = img.cols;
356 parallel_for_(Range(SIFT_IMG_BORDER, rows-SIFT_IMG_BORDER),
357 findScaleSpaceExtremaComputer(
358 o, i, threshold, idx, step, cols,
363 gauss_pyr, dog_pyr, tls_kpts_struct));
366 std::vector<std::vector<KeyPoint>*> kpt_vecs;
367 tls_kpts_struct.gather(kpt_vecs);
368 for (size_t i = 0; i < kpt_vecs.size(); ++i) {
369 keypoints.insert(keypoints.end(), kpt_vecs[i]->begin(), kpt_vecs[i]->end());
375 void calcSIFTDescriptor(
376 const Mat& img, Point2f ptf, float ori, float scl,
377 int d, int n, Mat& dst, int row
382 CV_CPU_DISPATCH(calcSIFTDescriptor, (img, ptf, ori, scl, d, n, dst, row),
383 CV_CPU_DISPATCH_MODES_ALL);
386 class calcDescriptorsComputer : public ParallelLoopBody
389 calcDescriptorsComputer(const std::vector<Mat>& _gpyr,
390 const std::vector<KeyPoint>& _keypoints,
395 keypoints(_keypoints),
396 descriptors(_descriptors),
397 nOctaveLayers(_nOctaveLayers),
398 firstOctave(_firstOctave) { }
400 void operator()( const cv::Range& range ) const CV_OVERRIDE
404 const int begin = range.start;
405 const int end = range.end;
407 static const int d = SIFT_DESCR_WIDTH, n = SIFT_DESCR_HIST_BINS;
409 for ( int i = begin; i<end; i++ )
411 KeyPoint kpt = keypoints[i];
414 unpackOctave(kpt, octave, layer, scale);
415 CV_Assert(octave >= firstOctave && layer <= nOctaveLayers+2);
416 float size=kpt.size*scale;
417 Point2f ptf(kpt.pt.x*scale, kpt.pt.y*scale);
418 const Mat& img = gpyr[(octave - firstOctave)*(nOctaveLayers + 3) + layer];
420 float angle = 360.f - kpt.angle;
421 if(std::abs(angle - 360.f) < FLT_EPSILON)
423 calcSIFTDescriptor(img, ptf, angle, size*0.5f, d, n, descriptors, i);
427 const std::vector<Mat>& gpyr;
428 const std::vector<KeyPoint>& keypoints;
434 static void calcDescriptors(const std::vector<Mat>& gpyr, const std::vector<KeyPoint>& keypoints,
435 Mat& descriptors, int nOctaveLayers, int firstOctave )
438 parallel_for_(Range(0, static_cast<int>(keypoints.size())), calcDescriptorsComputer(gpyr, keypoints, descriptors, nOctaveLayers, firstOctave));
441 //////////////////////////////////////////////////////////////////////////////////////////
443 SIFT_Impl::SIFT_Impl( int _nfeatures, int _nOctaveLayers,
444 double _contrastThreshold, double _edgeThreshold, double _sigma, int _descriptorType )
445 : nfeatures(_nfeatures), nOctaveLayers(_nOctaveLayers),
446 contrastThreshold(_contrastThreshold), edgeThreshold(_edgeThreshold), sigma(_sigma), descriptor_type(_descriptorType)
450 int SIFT_Impl::descriptorSize() const
452 return SIFT_DESCR_WIDTH*SIFT_DESCR_WIDTH*SIFT_DESCR_HIST_BINS;
455 int SIFT_Impl::descriptorType() const
457 return descriptor_type;
460 int SIFT_Impl::defaultNorm() const
466 void SIFT_Impl::detectAndCompute(InputArray _image, InputArray _mask,
467 std::vector<KeyPoint>& keypoints,
468 OutputArray _descriptors,
469 bool useProvidedKeypoints)
473 int firstOctave = -1, actualNOctaves = 0, actualNLayers = 0;
474 Mat image = _image.getMat(), mask = _mask.getMat();
476 if( image.empty() || image.depth() != CV_8U )
477 CV_Error( Error::StsBadArg, "image is empty or has incorrect depth (!=CV_8U)" );
479 if( !mask.empty() && mask.type() != CV_8UC1 )
480 CV_Error( Error::StsBadArg, "mask has incorrect type (!=CV_8UC1)" );
482 if( useProvidedKeypoints )
485 int maxOctave = INT_MIN;
486 for( size_t i = 0; i < keypoints.size(); i++ )
490 unpackOctave(keypoints[i], octave, layer, scale);
491 firstOctave = std::min(firstOctave, octave);
492 maxOctave = std::max(maxOctave, octave);
493 actualNLayers = std::max(actualNLayers, layer-2);
496 firstOctave = std::min(firstOctave, 0);
497 CV_Assert( firstOctave >= -1 && actualNLayers <= nOctaveLayers );
498 actualNOctaves = maxOctave - firstOctave + 1;
501 Mat base = createInitialImage(image, firstOctave < 0, (float)sigma);
502 std::vector<Mat> gpyr;
503 int nOctaves = actualNOctaves > 0 ? actualNOctaves : cvRound(std::log( (double)std::min( base.cols, base.rows ) ) / std::log(2.) - 2) - firstOctave;
505 //double t, tf = getTickFrequency();
506 //t = (double)getTickCount();
507 buildGaussianPyramid(base, gpyr, nOctaves);
509 //t = (double)getTickCount() - t;
510 //printf("pyramid construction time: %g\n", t*1000./tf);
512 if( !useProvidedKeypoints )
514 std::vector<Mat> dogpyr;
515 buildDoGPyramid(gpyr, dogpyr);
516 //t = (double)getTickCount();
517 findScaleSpaceExtrema(gpyr, dogpyr, keypoints);
518 KeyPointsFilter::removeDuplicatedSorted( keypoints );
521 KeyPointsFilter::retainBest(keypoints, nfeatures);
522 //t = (double)getTickCount() - t;
523 //printf("keypoint detection time: %g\n", t*1000./tf);
525 if( firstOctave < 0 )
526 for( size_t i = 0; i < keypoints.size(); i++ )
528 KeyPoint& kpt = keypoints[i];
529 float scale = 1.f/(float)(1 << -firstOctave);
530 kpt.octave = (kpt.octave & ~255) | ((kpt.octave + firstOctave) & 255);
536 KeyPointsFilter::runByPixelsMask( keypoints, mask );
540 // filter keypoints by mask
541 //KeyPointsFilter::runByPixelsMask( keypoints, mask );
544 if( _descriptors.needed() )
546 //t = (double)getTickCount();
547 int dsize = descriptorSize();
548 _descriptors.create((int)keypoints.size(), dsize, descriptor_type);
550 Mat descriptors = _descriptors.getMat();
551 calcDescriptors(gpyr, keypoints, descriptors, nOctaveLayers, firstOctave);
552 //t = (double)getTickCount() - t;
553 //printf("descriptor extraction time: %g\n", t*1000./tf);