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 //                          License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
16 // Third party copyrights are property of their respective owners.
17 //
18 // Redistribution and use in source and binary forms, with or without modification,
19 // are permitted provided that the following conditions are met:
20 //
21 //   * Redistribution's of source code must retain the above copyright notice,
22 //     this list of conditions and the following disclaimer.
23 //
24 //   * Redistribution's in binary form must reproduce the above copyright notice,
25 //     this list of conditions and the following disclaimer in the documentation
26 //     and/or other materials provided with the distribution.
27 //
28 //   * The name of the copyright holders may not be used to endorse or promote products
29 //     derived from this software without specific prior written permission.
30 //
31 // This software is provided by the copyright holders and contributors "as is" and
32 // any express or implied warranties, including, but not limited to, the implied
33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
34 // In no event shall the Intel Corporation or contributors be liable for any direct,
35 // indirect, incidental, special, exemplary, or consequential damages
36 // (including, but not limited to, procurement of substitute goods or services;
37 // loss of use, data, or profits; or business interruption) however caused
38 // and on any theory of liability, whether in contract, strict liability,
39 // or tort (including negligence or otherwise) arising in any way out of
40 // the use of this software, even if advised of the possibility of such damage.
41 //
42 //M*/
43 
44 #include "precomp.hpp"
45 
46 #include <algorithm>
47 #include <iterator>
48 #include <limits>
49 
50 namespace cv
51 {
52 
RANSACUpdateNumIters(double p,double ep,int modelPoints,int maxIters)53 int RANSACUpdateNumIters( double p, double ep, int modelPoints, int maxIters )
54 {
55     if( modelPoints <= 0 )
56         CV_Error( Error::StsOutOfRange, "the number of model points should be positive" );
57 
58     p = MAX(p, 0.);
59     p = MIN(p, 1.);
60     ep = MAX(ep, 0.);
61     ep = MIN(ep, 1.);
62 
63     // avoid inf's & nan's
64     double num = MAX(1. - p, DBL_MIN);
65     double denom = 1. - std::pow(1. - ep, modelPoints);
66     if( denom < DBL_MIN )
67         return 0;
68 
69     num = std::log(num);
70     denom = std::log(denom);
71 
72     return denom >= 0 || -num >= maxIters*(-denom) ? maxIters : cvRound(num/denom);
73 }
74 
75 
76 class RANSACPointSetRegistrator : public PointSetRegistrator
77 {
78 public:
RANSACPointSetRegistrator(const Ptr<PointSetRegistrator::Callback> & _cb=Ptr<PointSetRegistrator::Callback> (),int _modelPoints=0,double _threshold=0,double _confidence=0.99,int _maxIters=1000)79     RANSACPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& _cb=Ptr<PointSetRegistrator::Callback>(),
80                               int _modelPoints=0, double _threshold=0, double _confidence=0.99, int _maxIters=1000)
81     : cb(_cb), modelPoints(_modelPoints), threshold(_threshold), confidence(_confidence), maxIters(_maxIters)
82     {
83         checkPartialSubsets = false;
84     }
85 
findInliers(const Mat & m1,const Mat & m2,const Mat & model,Mat & err,Mat & mask,double thresh) const86     int findInliers( const Mat& m1, const Mat& m2, const Mat& model, Mat& err, Mat& mask, double thresh ) const
87     {
88         cb->computeError( m1, m2, model, err );
89         mask.create(err.size(), CV_8U);
90 
91         CV_Assert( err.isContinuous() && err.type() == CV_32F && mask.isContinuous() && mask.type() == CV_8U);
92         const float* errptr = err.ptr<float>();
93         uchar* maskptr = mask.ptr<uchar>();
94         float t = (float)(thresh*thresh);
95         int i, n = (int)err.total(), nz = 0;
96         for( i = 0; i < n; i++ )
97         {
98             int f = errptr[i] <= t;
99             maskptr[i] = (uchar)f;
100             nz += f;
101         }
102         return nz;
103     }
104 
getSubset(const Mat & m1,const Mat & m2,Mat & ms1,Mat & ms2,RNG & rng,int maxAttempts=1000) const105     bool getSubset( const Mat& m1, const Mat& m2,
106                     Mat& ms1, Mat& ms2, RNG& rng,
107                     int maxAttempts=1000 ) const
108     {
109         cv::AutoBuffer<int> _idx(modelPoints);
110         int* idx = _idx;
111         int i = 0, j, k, iters = 0;
112         int esz1 = (int)m1.elemSize(), esz2 = (int)m2.elemSize();
113         int d1 = m1.channels() > 1 ? m1.channels() : m1.cols;
114         int d2 = m2.channels() > 1 ? m2.channels() : m2.cols;
115         int count = m1.checkVector(d1), count2 = m2.checkVector(d2);
116         const int *m1ptr = m1.ptr<int>(), *m2ptr = m2.ptr<int>();
117 
118         ms1.create(modelPoints, 1, CV_MAKETYPE(m1.depth(), d1));
119         ms2.create(modelPoints, 1, CV_MAKETYPE(m2.depth(), d2));
120 
121         int *ms1ptr = ms1.ptr<int>(), *ms2ptr = ms2.ptr<int>();
122 
123         CV_Assert( count >= modelPoints && count == count2 );
124         CV_Assert( (esz1 % sizeof(int)) == 0 && (esz2 % sizeof(int)) == 0 );
125         esz1 /= sizeof(int);
126         esz2 /= sizeof(int);
127 
128         for(; iters < maxAttempts; iters++)
129         {
130             for( i = 0; i < modelPoints && iters < maxAttempts; )
131             {
132                 int idx_i = 0;
133                 for(;;)
134                 {
135                     idx_i = idx[i] = rng.uniform(0, count);
136                     for( j = 0; j < i; j++ )
137                         if( idx_i == idx[j] )
138                             break;
139                     if( j == i )
140                         break;
141                 }
142                 for( k = 0; k < esz1; k++ )
143                     ms1ptr[i*esz1 + k] = m1ptr[idx_i*esz1 + k];
144                 for( k = 0; k < esz2; k++ )
145                     ms2ptr[i*esz2 + k] = m2ptr[idx_i*esz2 + k];
146                 if( checkPartialSubsets && !cb->checkSubset( ms1, ms2, i+1 ))
147                 {
148                     // we may have selected some bad points;
149                     // so, let's remove some of them randomly
150                     i = rng.uniform(0, i+1);
151                     iters++;
152                     continue;
153                 }
154                 i++;
155             }
156             if( !checkPartialSubsets && i == modelPoints && !cb->checkSubset(ms1, ms2, i))
157                 continue;
158             break;
159         }
160 
161         return i == modelPoints && iters < maxAttempts;
162     }
163 
run(InputArray _m1,InputArray _m2,OutputArray _model,OutputArray _mask) const164     bool run(InputArray _m1, InputArray _m2, OutputArray _model, OutputArray _mask) const
165     {
166         bool result = false;
167         Mat m1 = _m1.getMat(), m2 = _m2.getMat();
168         Mat err, mask, model, bestModel, ms1, ms2;
169 
170         int iter, niters = MAX(maxIters, 1);
171         int d1 = m1.channels() > 1 ? m1.channels() : m1.cols;
172         int d2 = m2.channels() > 1 ? m2.channels() : m2.cols;
173         int count = m1.checkVector(d1), count2 = m2.checkVector(d2), maxGoodCount = 0;
174 
175         RNG rng((uint64)-1);
176 
177         CV_Assert( cb );
178         CV_Assert( confidence > 0 && confidence < 1 );
179 
180         CV_Assert( count >= 0 && count2 == count );
181         if( count < modelPoints )
182             return false;
183 
184         Mat bestMask0, bestMask;
185 
186         if( _mask.needed() )
187         {
188             _mask.create(count, 1, CV_8U, -1, true);
189             bestMask0 = bestMask = _mask.getMat();
190             CV_Assert( (bestMask.cols == 1 || bestMask.rows == 1) && (int)bestMask.total() == count );
191         }
192         else
193         {
194             bestMask.create(count, 1, CV_8U);
195             bestMask0 = bestMask;
196         }
197 
198         if( count == modelPoints )
199         {
200             if( cb->runKernel(m1, m2, bestModel) <= 0 )
201                 return false;
202             bestModel.copyTo(_model);
203             bestMask.setTo(Scalar::all(1));
204             return true;
205         }
206 
207         for( iter = 0; iter < niters; iter++ )
208         {
209             int i, goodCount, nmodels;
210             if( count > modelPoints )
211             {
212                 bool found = getSubset( m1, m2, ms1, ms2, rng, 10000 );
213                 if( !found )
214                 {
215                     if( iter == 0 )
216                         return false;
217                     break;
218                 }
219             }
220 
221             nmodels = cb->runKernel( ms1, ms2, model );
222             if( nmodels <= 0 )
223                 continue;
224             CV_Assert( model.rows % nmodels == 0 );
225             Size modelSize(model.cols, model.rows/nmodels);
226 
227             for( i = 0; i < nmodels; i++ )
228             {
229                 Mat model_i = model.rowRange( i*modelSize.height, (i+1)*modelSize.height );
230                 goodCount = findInliers( m1, m2, model_i, err, mask, threshold );
231 
232                 if( goodCount > MAX(maxGoodCount, modelPoints-1) )
233                 {
234                     std::swap(mask, bestMask);
235                     model_i.copyTo(bestModel);
236                     maxGoodCount = goodCount;
237                     niters = RANSACUpdateNumIters( confidence, (double)(count - goodCount)/count, modelPoints, niters );
238                 }
239             }
240         }
241 
242         if( maxGoodCount > 0 )
243         {
244             if( bestMask.data != bestMask0.data )
245             {
246                 if( bestMask.size() == bestMask0.size() )
247                     bestMask.copyTo(bestMask0);
248                 else
249                     transpose(bestMask, bestMask0);
250             }
251             bestModel.copyTo(_model);
252             result = true;
253         }
254         else
255             _model.release();
256 
257         return result;
258     }
259 
setCallback(const Ptr<PointSetRegistrator::Callback> & _cb)260     void setCallback(const Ptr<PointSetRegistrator::Callback>& _cb) { cb = _cb; }
261 
262     Ptr<PointSetRegistrator::Callback> cb;
263     int modelPoints;
264     bool checkPartialSubsets;
265     double threshold;
266     double confidence;
267     int maxIters;
268 };
269 
270 class LMeDSPointSetRegistrator : public RANSACPointSetRegistrator
271 {
272 public:
LMeDSPointSetRegistrator(const Ptr<PointSetRegistrator::Callback> & _cb=Ptr<PointSetRegistrator::Callback> (),int _modelPoints=0,double _confidence=0.99,int _maxIters=1000)273     LMeDSPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& _cb=Ptr<PointSetRegistrator::Callback>(),
274                               int _modelPoints=0, double _confidence=0.99, int _maxIters=1000)
275     : RANSACPointSetRegistrator(_cb, _modelPoints, 0, _confidence, _maxIters) {}
276 
run(InputArray _m1,InputArray _m2,OutputArray _model,OutputArray _mask) const277     bool run(InputArray _m1, InputArray _m2, OutputArray _model, OutputArray _mask) const
278     {
279         const double outlierRatio = 0.45;
280         bool result = false;
281         Mat m1 = _m1.getMat(), m2 = _m2.getMat();
282         Mat ms1, ms2, err, errf, model, bestModel, mask, mask0;
283 
284         int d1 = m1.channels() > 1 ? m1.channels() : m1.cols;
285         int d2 = m2.channels() > 1 ? m2.channels() : m2.cols;
286         int count = m1.checkVector(d1), count2 = m2.checkVector(d2);
287         double minMedian = DBL_MAX, sigma;
288 
289         RNG rng((uint64)-1);
290 
291         CV_Assert( cb );
292         CV_Assert( confidence > 0 && confidence < 1 );
293 
294         CV_Assert( count >= 0 && count2 == count );
295         if( count < modelPoints )
296             return false;
297 
298         if( _mask.needed() )
299         {
300             _mask.create(count, 1, CV_8U, -1, true);
301             mask0 = mask = _mask.getMat();
302             CV_Assert( (mask.cols == 1 || mask.rows == 1) && (int)mask.total() == count );
303         }
304 
305         if( count == modelPoints )
306         {
307             if( cb->runKernel(m1, m2, bestModel) <= 0 )
308                 return false;
309             bestModel.copyTo(_model);
310             mask.setTo(Scalar::all(1));
311             return true;
312         }
313 
314         int iter, niters = RANSACUpdateNumIters(confidence, outlierRatio, modelPoints, maxIters);
315         niters = MAX(niters, 3);
316 
317         for( iter = 0; iter < niters; iter++ )
318         {
319             int i, nmodels;
320             if( count > modelPoints )
321             {
322                 bool found = getSubset( m1, m2, ms1, ms2, rng );
323                 if( !found )
324                 {
325                     if( iter == 0 )
326                         return false;
327                     break;
328                 }
329             }
330 
331             nmodels = cb->runKernel( ms1, ms2, model );
332             if( nmodels <= 0 )
333                 continue;
334 
335             CV_Assert( model.rows % nmodels == 0 );
336             Size modelSize(model.cols, model.rows/nmodels);
337 
338             for( i = 0; i < nmodels; i++ )
339             {
340                 Mat model_i = model.rowRange( i*modelSize.height, (i+1)*modelSize.height );
341                 cb->computeError( m1, m2, model_i, err );
342                 if( err.depth() != CV_32F )
343                     err.convertTo(errf, CV_32F);
344                 else
345                     errf = err;
346                 CV_Assert( errf.isContinuous() && errf.type() == CV_32F && (int)errf.total() == count );
347                 std::sort(errf.ptr<int>(), errf.ptr<int>() + count);
348 
349                 double median = count % 2 != 0 ?
350                 errf.at<float>(count/2) : (errf.at<float>(count/2-1) + errf.at<float>(count/2))*0.5;
351 
352                 if( median < minMedian )
353                 {
354                     minMedian = median;
355                     model_i.copyTo(bestModel);
356                 }
357             }
358         }
359 
360         if( minMedian < DBL_MAX )
361         {
362             sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*std::sqrt(minMedian);
363             sigma = MAX( sigma, 0.001 );
364 
365             count = findInliers( m1, m2, bestModel, err, mask, sigma );
366             if( _mask.needed() && mask0.data != mask.data )
367             {
368                 if( mask0.size() == mask.size() )
369                     mask.copyTo(mask0);
370                 else
371                     transpose(mask, mask0);
372             }
373             bestModel.copyTo(_model);
374             result = count >= modelPoints;
375         }
376         else
377             _model.release();
378 
379         return result;
380     }
381 
382 };
383 
createRANSACPointSetRegistrator(const Ptr<PointSetRegistrator::Callback> & _cb,int _modelPoints,double _threshold,double _confidence,int _maxIters)384 Ptr<PointSetRegistrator> createRANSACPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& _cb,
385                                                          int _modelPoints, double _threshold,
386                                                          double _confidence, int _maxIters)
387 {
388     return Ptr<PointSetRegistrator>(
389         new RANSACPointSetRegistrator(_cb, _modelPoints, _threshold, _confidence, _maxIters));
390 }
391 
392 
createLMeDSPointSetRegistrator(const Ptr<PointSetRegistrator::Callback> & _cb,int _modelPoints,double _confidence,int _maxIters)393 Ptr<PointSetRegistrator> createLMeDSPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& _cb,
394                              int _modelPoints, double _confidence, int _maxIters)
395 {
396     return Ptr<PointSetRegistrator>(
397         new LMeDSPointSetRegistrator(_cb, _modelPoints, _confidence, _maxIters));
398 }
399 
400 
401 class Affine3DEstimatorCallback : public PointSetRegistrator::Callback
402 {
403 public:
runKernel(InputArray _m1,InputArray _m2,OutputArray _model) const404     int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const
405     {
406         Mat m1 = _m1.getMat(), m2 = _m2.getMat();
407         const Point3f* from = m1.ptr<Point3f>();
408         const Point3f* to   = m2.ptr<Point3f>();
409 
410         const int N = 12;
411         double buf[N*N + N + N];
412         Mat A(N, N, CV_64F, &buf[0]);
413         Mat B(N, 1, CV_64F, &buf[0] + N*N);
414         Mat X(N, 1, CV_64F, &buf[0] + N*N + N);
415         double* Adata = A.ptr<double>();
416         double* Bdata = B.ptr<double>();
417         A = Scalar::all(0);
418 
419         for( int i = 0; i < (N/3); i++ )
420         {
421             Bdata[i*3] = to[i].x;
422             Bdata[i*3+1] = to[i].y;
423             Bdata[i*3+2] = to[i].z;
424 
425             double *aptr = Adata + i*3*N;
426             for(int k = 0; k < 3; ++k)
427             {
428                 aptr[0] = from[i].x;
429                 aptr[1] = from[i].y;
430                 aptr[2] = from[i].z;
431                 aptr[3] = 1.0;
432                 aptr += 16;
433             }
434         }
435 
436         solve(A, B, X, DECOMP_SVD);
437         X.reshape(1, 3).copyTo(_model);
438 
439         return 1;
440     }
441 
computeError(InputArray _m1,InputArray _m2,InputArray _model,OutputArray _err) const442     void computeError( InputArray _m1, InputArray _m2, InputArray _model, OutputArray _err ) const
443     {
444         Mat m1 = _m1.getMat(), m2 = _m2.getMat(), model = _model.getMat();
445         const Point3f* from = m1.ptr<Point3f>();
446         const Point3f* to   = m2.ptr<Point3f>();
447         const double* F = model.ptr<double>();
448 
449         int count = m1.checkVector(3);
450         CV_Assert( count > 0 );
451 
452         _err.create(count, 1, CV_32F);
453         Mat err = _err.getMat();
454         float* errptr = err.ptr<float>();
455 
456         for(int i = 0; i < count; i++ )
457         {
458             const Point3f& f = from[i];
459             const Point3f& t = to[i];
460 
461             double a = F[0]*f.x + F[1]*f.y + F[ 2]*f.z + F[ 3] - t.x;
462             double b = F[4]*f.x + F[5]*f.y + F[ 6]*f.z + F[ 7] - t.y;
463             double c = F[8]*f.x + F[9]*f.y + F[10]*f.z + F[11] - t.z;
464 
465             errptr[i] = (float)std::sqrt(a*a + b*b + c*c);
466         }
467     }
468 
checkSubset(InputArray _ms1,InputArray _ms2,int count) const469     bool checkSubset( InputArray _ms1, InputArray _ms2, int count ) const
470     {
471         const float threshold = 0.996f;
472         Mat ms1 = _ms1.getMat(), ms2 = _ms2.getMat();
473 
474         for( int inp = 1; inp <= 2; inp++ )
475         {
476             int j, k, i = count - 1;
477             const Mat* msi = inp == 1 ? &ms1 : &ms2;
478             const Point3f* ptr = msi->ptr<Point3f>();
479 
480             CV_Assert( count <= msi->rows );
481 
482             // check that the i-th selected point does not belong
483             // to a line connecting some previously selected points
484             for(j = 0; j < i; ++j)
485             {
486                 Point3f d1 = ptr[j] - ptr[i];
487                 float n1 = d1.x*d1.x + d1.y*d1.y;
488 
489                 for(k = 0; k < j; ++k)
490                 {
491                     Point3f d2 = ptr[k] - ptr[i];
492                     float denom = (d2.x*d2.x + d2.y*d2.y)*n1;
493                     float num = d1.x*d2.x + d1.y*d2.y;
494 
495                     if( num*num > threshold*threshold*denom )
496                         return false;
497                 }
498             }
499         }
500         return true;
501     }
502 };
503 
504 }
505 
estimateAffine3D(InputArray _from,InputArray _to,OutputArray _out,OutputArray _inliers,double param1,double param2)506 int cv::estimateAffine3D(InputArray _from, InputArray _to,
507                          OutputArray _out, OutputArray _inliers,
508                          double param1, double param2)
509 {
510     Mat from = _from.getMat(), to = _to.getMat();
511     int count = from.checkVector(3);
512 
513     CV_Assert( count >= 0 && to.checkVector(3) == count );
514 
515     Mat dFrom, dTo;
516     from.convertTo(dFrom, CV_32F);
517     to.convertTo(dTo, CV_32F);
518     dFrom = dFrom.reshape(3, count);
519     dTo = dTo.reshape(3, count);
520 
521     const double epsilon = DBL_EPSILON;
522     param1 = param1 <= 0 ? 3 : param1;
523     param2 = (param2 < epsilon) ? 0.99 : (param2 > 1 - epsilon) ? 0.99 : param2;
524 
525     return createRANSACPointSetRegistrator(makePtr<Affine3DEstimatorCallback>(), 4, param1, param2)->run(dFrom, dTo, _out, _inliers);
526 }
527