831750862b7ae34b86ca3335f9b704ba98dd5cbd
[platform/upstream/opencv.git] / modules / features2d / src / sift.dispatch.cpp
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
76 #include "sift.simd.hpp"
77 #include "sift.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX2,...,BASELINE based on CMakeLists.txt content
78
79 namespace cv {
80
81 /*!
82  SIFT implementation.
83
84  The class implements SIFT algorithm by D. Lowe.
85  */
86 class SIFT_Impl : public SIFT
87 {
88 public:
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 );
92
93     //! returns the descriptor size in floats (128)
94     int descriptorSize() const CV_OVERRIDE;
95
96     //! returns the descriptor type
97     int descriptorType() const CV_OVERRIDE;
98
99     //! returns the default norm type
100     int defaultNorm() const CV_OVERRIDE;
101
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;
108
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;
113
114 protected:
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;
121 };
122
123 Ptr<SIFT> SIFT::create( int _nfeatures, int _nOctaveLayers,
124                      double _contrastThreshold, double _edgeThreshold, double _sigma )
125 {
126     CV_TRACE_FUNCTION();
127
128     return makePtr<SIFT_Impl>(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma, CV_32F);
129 }
130
131 Ptr<SIFT> SIFT::create( int _nfeatures, int _nOctaveLayers,
132                      double _contrastThreshold, double _edgeThreshold, double _sigma, int _descriptorType )
133 {
134     CV_TRACE_FUNCTION();
135
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);
139 }
140
141 String SIFT::getDefaultName() const
142 {
143     return (Feature2D::getDefaultName() + ".SIFT");
144 }
145
146 static inline void
147 unpackOctave(const KeyPoint& kpt, int& octave, int& layer, float& scale)
148 {
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);
153 }
154
155 static Mat createInitialImage( const Mat& img, bool doubleImageSize, float sigma )
156 {
157     CV_TRACE_FUNCTION();
158
159     Mat gray, gray_fpt;
160     if( img.channels() == 3 || img.channels() == 4 )
161     {
162         cvtColor(img, gray, COLOR_BGR2GRAY);
163         gray.convertTo(gray_fpt, DataType<sift_wt>::type, SIFT_FIXPT_SCALE, 0);
164     }
165     else
166         img.convertTo(gray_fpt, DataType<sift_wt>::type, SIFT_FIXPT_SCALE, 0);
167
168     float sig_diff;
169
170     if( doubleImageSize )
171     {
172         sig_diff = sqrtf( std::max(sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA * 4, 0.01f) );
173         Mat dbl;
174 #if DoG_TYPE_SHORT
175         resize(gray_fpt, dbl, Size(gray_fpt.cols*2, gray_fpt.rows*2), 0, 0, INTER_LINEAR_EXACT);
176 #else
177         resize(gray_fpt, dbl, Size(gray_fpt.cols*2, gray_fpt.rows*2), 0, 0, INTER_LINEAR);
178 #endif
179         Mat result;
180         GaussianBlur(dbl, result, Size(), sig_diff, sig_diff);
181         return result;
182     }
183     else
184     {
185         sig_diff = sqrtf( std::max(sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA, 0.01f) );
186         Mat result;
187         GaussianBlur(gray_fpt, result, Size(), sig_diff, sig_diff);
188         return result;
189     }
190 }
191
192
193 void SIFT_Impl::buildGaussianPyramid( const Mat& base, std::vector<Mat>& pyr, int nOctaves ) const
194 {
195     CV_TRACE_FUNCTION();
196
197     std::vector<double> sig(nOctaveLayers + 3);
198     pyr.resize(nOctaves*(nOctaveLayers + 3));
199
200     // precompute Gaussian sigmas using the following formula:
201     //  \sigma_{total}^2 = \sigma_{i}^2 + \sigma_{i-1}^2
202     sig[0] = sigma;
203     double k = std::pow( 2., 1. / nOctaveLayers );
204     for( int i = 1; i < nOctaveLayers + 3; i++ )
205     {
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);
209     }
210
211     for( int o = 0; o < nOctaves; o++ )
212     {
213         for( int i = 0; i < nOctaveLayers + 3; i++ )
214         {
215             Mat& dst = pyr[o*(nOctaveLayers + 3) + i];
216             if( o == 0  &&  i == 0 )
217                 dst = base;
218             // base of new octave is halved image from end of previous octave
219             else if( i == 0 )
220             {
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);
224             }
225             else
226             {
227                 const Mat& src = pyr[o*(nOctaveLayers + 3) + i-1];
228                 GaussianBlur(src, dst, Size(), sig[i], sig[i]);
229             }
230         }
231     }
232 }
233
234
235 class buildDoGPyramidComputer : public ParallelLoopBody
236 {
237 public:
238     buildDoGPyramidComputer(
239         int _nOctaveLayers,
240         const std::vector<Mat>& _gpyr,
241         std::vector<Mat>& _dogpyr)
242         : nOctaveLayers(_nOctaveLayers),
243           gpyr(_gpyr),
244           dogpyr(_dogpyr) { }
245
246     void operator()( const cv::Range& range ) const CV_OVERRIDE
247     {
248         CV_TRACE_FUNCTION();
249
250         const int begin = range.start;
251         const int end = range.end;
252
253         for( int a = begin; a < end; a++ )
254         {
255             const int o = a / (nOctaveLayers + 2);
256             const int i = a % (nOctaveLayers + 2);
257
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);
262         }
263     }
264
265 private:
266     int nOctaveLayers;
267     const std::vector<Mat>& gpyr;
268     std::vector<Mat>& dogpyr;
269 };
270
271 void SIFT_Impl::buildDoGPyramid( const std::vector<Mat>& gpyr, std::vector<Mat>& dogpyr ) const
272 {
273     CV_TRACE_FUNCTION();
274
275     int nOctaves = (int)gpyr.size()/(nOctaveLayers + 3);
276     dogpyr.resize( nOctaves*(nOctaveLayers + 2) );
277
278     parallel_for_(Range(0, nOctaves * (nOctaveLayers + 2)), buildDoGPyramidComputer(nOctaveLayers, gpyr, dogpyr));
279 }
280
281 class findScaleSpaceExtremaComputer : public ParallelLoopBody
282 {
283 public:
284     findScaleSpaceExtremaComputer(
285         int _o,
286         int _i,
287         int _threshold,
288         int _idx,
289         int _step,
290         int _cols,
291         int _nOctaveLayers,
292         double _contrastThreshold,
293         double _edgeThreshold,
294         double _sigma,
295         const std::vector<Mat>& _gauss_pyr,
296         const std::vector<Mat>& _dog_pyr,
297         TLSData<std::vector<KeyPoint> > &_tls_kpts_struct)
298
299         : o(_o),
300           i(_i),
301           threshold(_threshold),
302           idx(_idx),
303           step(_step),
304           cols(_cols),
305           nOctaveLayers(_nOctaveLayers),
306           contrastThreshold(_contrastThreshold),
307           edgeThreshold(_edgeThreshold),
308           sigma(_sigma),
309           gauss_pyr(_gauss_pyr),
310           dog_pyr(_dog_pyr),
311           tls_kpts_struct(_tls_kpts_struct) { }
312     void operator()( const cv::Range& range ) const CV_OVERRIDE
313     {
314         CV_TRACE_FUNCTION();
315
316         std::vector<KeyPoint>& kpts = tls_kpts_struct.getRef();
317
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);
320     }
321 private:
322     int o, i;
323     int threshold;
324     int idx, step, cols;
325     int nOctaveLayers;
326     double contrastThreshold;
327     double edgeThreshold;
328     double sigma;
329     const std::vector<Mat>& gauss_pyr;
330     const std::vector<Mat>& dog_pyr;
331     TLSData<std::vector<KeyPoint> > &tls_kpts_struct;
332 };
333
334 //
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
339 {
340     CV_TRACE_FUNCTION();
341
342     const int nOctaves = (int)gauss_pyr.size()/(nOctaveLayers + 3);
343     const int threshold = cvFloor(0.5 * contrastThreshold / nOctaveLayers * 255 * SIFT_FIXPT_SCALE);
344
345     keypoints.clear();
346     TLSDataAccumulator<std::vector<KeyPoint> > tls_kpts_struct;
347
348     for( int o = 0; o < nOctaves; o++ )
349         for( int i = 1; i <= nOctaveLayers; i++ )
350         {
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;
355
356             parallel_for_(Range(SIFT_IMG_BORDER, rows-SIFT_IMG_BORDER),
357                 findScaleSpaceExtremaComputer(
358                     o, i, threshold, idx, step, cols,
359                     nOctaveLayers,
360                     contrastThreshold,
361                     edgeThreshold,
362                     sigma,
363                     gauss_pyr, dog_pyr, tls_kpts_struct));
364         }
365
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());
370     }
371 }
372
373
374 static
375 void calcSIFTDescriptor(
376         const Mat& img, Point2f ptf, float ori, float scl,
377         int d, int n, Mat& dst, int row
378 )
379 {
380     CV_TRACE_FUNCTION();
381
382     CV_CPU_DISPATCH(calcSIFTDescriptor, (img, ptf, ori, scl, d, n, dst, row),
383         CV_CPU_DISPATCH_MODES_ALL);
384 }
385
386 class calcDescriptorsComputer : public ParallelLoopBody
387 {
388 public:
389     calcDescriptorsComputer(const std::vector<Mat>& _gpyr,
390                             const std::vector<KeyPoint>& _keypoints,
391                             Mat& _descriptors,
392                             int _nOctaveLayers,
393                             int _firstOctave)
394         : gpyr(_gpyr),
395           keypoints(_keypoints),
396           descriptors(_descriptors),
397           nOctaveLayers(_nOctaveLayers),
398           firstOctave(_firstOctave) { }
399
400     void operator()( const cv::Range& range ) const CV_OVERRIDE
401     {
402         CV_TRACE_FUNCTION();
403
404         const int begin = range.start;
405         const int end = range.end;
406
407         static const int d = SIFT_DESCR_WIDTH, n = SIFT_DESCR_HIST_BINS;
408
409         for ( int i = begin; i<end; i++ )
410         {
411             KeyPoint kpt = keypoints[i];
412             int octave, layer;
413             float scale;
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];
419
420             float angle = 360.f - kpt.angle;
421             if(std::abs(angle - 360.f) < FLT_EPSILON)
422                 angle = 0.f;
423             calcSIFTDescriptor(img, ptf, angle, size*0.5f, d, n, descriptors, i);
424         }
425     }
426 private:
427     const std::vector<Mat>& gpyr;
428     const std::vector<KeyPoint>& keypoints;
429     Mat& descriptors;
430     int nOctaveLayers;
431     int firstOctave;
432 };
433
434 static void calcDescriptors(const std::vector<Mat>& gpyr, const std::vector<KeyPoint>& keypoints,
435                             Mat& descriptors, int nOctaveLayers, int firstOctave )
436 {
437     CV_TRACE_FUNCTION();
438     parallel_for_(Range(0, static_cast<int>(keypoints.size())), calcDescriptorsComputer(gpyr, keypoints, descriptors, nOctaveLayers, firstOctave));
439 }
440
441 //////////////////////////////////////////////////////////////////////////////////////////
442
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)
447 {
448 }
449
450 int SIFT_Impl::descriptorSize() const
451 {
452     return SIFT_DESCR_WIDTH*SIFT_DESCR_WIDTH*SIFT_DESCR_HIST_BINS;
453 }
454
455 int SIFT_Impl::descriptorType() const
456 {
457     return descriptor_type;
458 }
459
460 int SIFT_Impl::defaultNorm() const
461 {
462     return NORM_L2;
463 }
464
465
466 void SIFT_Impl::detectAndCompute(InputArray _image, InputArray _mask,
467                       std::vector<KeyPoint>& keypoints,
468                       OutputArray _descriptors,
469                       bool useProvidedKeypoints)
470 {
471     CV_TRACE_FUNCTION();
472
473     int firstOctave = -1, actualNOctaves = 0, actualNLayers = 0;
474     Mat image = _image.getMat(), mask = _mask.getMat();
475
476     if( image.empty() || image.depth() != CV_8U )
477         CV_Error( Error::StsBadArg, "image is empty or has incorrect depth (!=CV_8U)" );
478
479     if( !mask.empty() && mask.type() != CV_8UC1 )
480         CV_Error( Error::StsBadArg, "mask has incorrect type (!=CV_8UC1)" );
481
482     if( useProvidedKeypoints )
483     {
484         firstOctave = 0;
485         int maxOctave = INT_MIN;
486         for( size_t i = 0; i < keypoints.size(); i++ )
487         {
488             int octave, layer;
489             float scale;
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);
494         }
495
496         firstOctave = std::min(firstOctave, 0);
497         CV_Assert( firstOctave >= -1 && actualNLayers <= nOctaveLayers );
498         actualNOctaves = maxOctave - firstOctave + 1;
499     }
500
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;
504
505     //double t, tf = getTickFrequency();
506     //t = (double)getTickCount();
507     buildGaussianPyramid(base, gpyr, nOctaves);
508
509     //t = (double)getTickCount() - t;
510     //printf("pyramid construction time: %g\n", t*1000./tf);
511
512     if( !useProvidedKeypoints )
513     {
514         std::vector<Mat> dogpyr;
515         buildDoGPyramid(gpyr, dogpyr);
516         //t = (double)getTickCount();
517         findScaleSpaceExtrema(gpyr, dogpyr, keypoints);
518         KeyPointsFilter::removeDuplicatedSorted( keypoints );
519
520         if( nfeatures > 0 )
521             KeyPointsFilter::retainBest(keypoints, nfeatures);
522         //t = (double)getTickCount() - t;
523         //printf("keypoint detection time: %g\n", t*1000./tf);
524
525         if( firstOctave < 0 )
526             for( size_t i = 0; i < keypoints.size(); i++ )
527             {
528                 KeyPoint& kpt = keypoints[i];
529                 float scale = 1.f/(float)(1 << -firstOctave);
530                 kpt.octave = (kpt.octave & ~255) | ((kpt.octave + firstOctave) & 255);
531                 kpt.pt *= scale;
532                 kpt.size *= scale;
533             }
534
535         if( !mask.empty() )
536             KeyPointsFilter::runByPixelsMask( keypoints, mask );
537     }
538     else
539     {
540         // filter keypoints by mask
541         //KeyPointsFilter::runByPixelsMask( keypoints, mask );
542     }
543
544     if( _descriptors.needed() )
545     {
546         //t = (double)getTickCount();
547         int dsize = descriptorSize();
548         _descriptors.create((int)keypoints.size(), dsize, descriptor_type);
549
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);
554     }
555 }
556
557 }