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