Update the changelog
[opencv] / cv / src / cvfundam.cpp
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 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "_cv.h"
43
44 /* Evaluation of Fundamental Matrix from point correspondences.
45    The original code has been written by Valery Mosyagin */
46
47 /* The algorithms (except for RANSAC) and the notation have been taken from
48    Zhengyou Zhang's research report
49    "Determining the Epipolar Geometry and its Uncertainty: A Review"
50    that can be found at http://www-sop.inria.fr/robotvis/personnel/zzhang/zzhang-eng.html */
51
52 /************************************** 7-point algorithm *******************************/
53 static int
54 icvFMatrix_7Point( const CvPoint2D64f* m0, const CvPoint2D64f* m1, double* fmatrix )
55 {
56     double a[7*9], w[7], v[9*9], c[4], r[3];
57     double* f1, *f2;
58     double t0, t1, t2;
59     CvMat A = cvMat( 7, 9, CV_64F, a );
60     CvMat V = cvMat( 9, 9, CV_64F, v );
61     CvMat W = cvMat( 7, 1, CV_64F, w );
62     CvMat coeffs = cvMat( 1, 4, CV_64F, c );
63     CvMat roots = cvMat( 1, 3, CV_64F, r );
64     int i, k, n;
65
66     assert( m0 && m1 && fmatrix );
67
68     // form a linear system: i-th row of A(=a) represents
69     // the equation: (m1[i], 1)'*F*(m0[i], 1) = 0
70     for( i = 0; i < 7; i++ )
71     {
72         double x0 = m0[i].x, y0 = m0[i].y;
73         double x1 = m1[i].x, y1 = m1[i].y;
74
75         a[i*9+0] = x1*x0;
76         a[i*9+1] = x1*y0;
77         a[i*9+2] = x1;
78         a[i*9+3] = y1*x0;
79         a[i*9+4] = y1*y0;
80         a[i*9+5] = y1;
81         a[i*9+6] = x0;
82         a[i*9+7] = y0;
83         a[i*9+8] = 1;
84     }
85
86     // A*(f11 f12 ... f33)' = 0 is singular (7 equations for 9 variables), so
87     // the solution is linear subspace of dimensionality 2.
88     // => use the last two singular vectors as a basis of the space
89     // (according to SVD properties)
90     cvSVD( &A, &W, 0, &V, CV_SVD_MODIFY_A + CV_SVD_V_T );
91     f1 = v + 7*9;
92     f2 = v + 8*9;
93
94     // f1, f2 is a basis => lambda*f1 + mu*f2 is an arbitrary f. matrix.
95     // as it is determined up to a scale, normalize lambda & mu (lambda + mu = 1),
96     // so f ~ lambda*f1 + (1 - lambda)*f2.
97     // use the additional constraint det(f) = det(lambda*f1 + (1-lambda)*f2) to find lambda.
98     // it will be a cubic equation.
99     // find c - polynomial coefficients.
100     for( i = 0; i < 9; i++ )
101         f1[i] -= f2[i];
102
103     t0 = f2[4]*f2[8] - f2[5]*f2[7];
104     t1 = f2[3]*f2[8] - f2[5]*f2[6];
105     t2 = f2[3]*f2[7] - f2[4]*f2[6];
106
107     c[3] = f2[0]*t0 - f2[1]*t1 + f2[2]*t2;
108
109     c[2] = f1[0]*t0 - f1[1]*t1 + f1[2]*t2 -
110            f1[3]*(f2[1]*f2[8] - f2[2]*f2[7]) +
111            f1[4]*(f2[0]*f2[8] - f2[2]*f2[6]) -
112            f1[5]*(f2[0]*f2[7] - f2[1]*f2[6]) +
113            f1[6]*(f2[1]*f2[5] - f2[2]*f2[4]) -
114            f1[7]*(f2[0]*f2[5] - f2[2]*f2[3]) +
115            f1[8]*(f2[0]*f2[4] - f2[1]*f2[3]);
116
117     t0 = f1[4]*f1[8] - f1[5]*f1[7];
118     t1 = f1[3]*f1[8] - f1[5]*f1[6];
119     t2 = f1[3]*f1[7] - f1[4]*f1[6];
120
121     c[1] = f2[0]*t0 - f2[1]*t1 + f2[2]*t2 -
122            f2[3]*(f1[1]*f1[8] - f1[2]*f1[7]) +
123            f2[4]*(f1[0]*f1[8] - f1[2]*f1[6]) -
124            f2[5]*(f1[0]*f1[7] - f1[1]*f1[6]) +
125            f2[6]*(f1[1]*f1[5] - f1[2]*f1[4]) -
126            f2[7]*(f1[0]*f1[5] - f1[2]*f1[3]) +
127            f2[8]*(f1[0]*f1[4] - f1[1]*f1[3]);
128
129     c[0] = f1[0]*t0 - f1[1]*t1 + f1[2]*t2;
130
131     // solve the cubic equation; there can be 1 to 3 roots ...
132     n = cvSolveCubic( &coeffs, &roots );
133
134     if( n < 1 || n > 3 )
135         return n;
136
137     for( k = 0; k < n; k++, fmatrix += 9 )
138     {
139         // for each root form the fundamental matrix
140         double lambda = r[k], mu = 1.;
141         double s = f1[8]*r[k] + f2[8];
142
143         // normalize each matrix, so that F(3,3) (~fmatrix[8]) == 1
144         if( fabs(s) > DBL_EPSILON )
145         {
146             mu = 1./s;
147             lambda *= mu;
148             fmatrix[8] = 1.;
149         }
150         else
151             fmatrix[8] = 0.;
152
153         for( i = 0; i < 8; i++ )
154             fmatrix[i] = f1[i]*lambda + f2[i]*mu;
155     }
156
157     return n;
158 }
159
160
161 /*************************************** 8-point algorithm ******************************/
162 static int
163 icvFMatrix_8Point( const CvPoint2D64f* m0, const CvPoint2D64f* m1,
164                    const uchar* mask, int count, double* fmatrix )
165 {
166     int result = 0;
167     CvMat* A = 0;
168
169     double w[9], v[9*9];
170     CvMat W = cvMat( 1, 9, CV_64F, w);
171     CvMat V = cvMat( 9, 9, CV_64F, v);
172     CvMat U, F0, TF;
173
174     int i, good_count = 0;
175     CvPoint2D64f m0c = {0,0}, m1c = {0,0};
176     double t, scale0 = 0, scale1 = 0;
177     double* a;
178     int a_step;
179
180     CV_FUNCNAME( "icvFMatrix_8Point" );
181
182     __BEGIN__;
183
184     assert( m0 && m1 && fmatrix );
185
186     // compute centers and average distances for each of the two point sets
187     for( i = 0; i < count; i++ )
188         if( !mask || mask[i] )
189         {
190             double x = m0[i].x, y = m0[i].y;
191             m0c.x += x; m0c.y += y;
192
193             x = m1[i].x, y = m1[i].y;
194             m1c.x += x; m1c.y += y;
195             good_count++;
196         }
197
198     if( good_count < 8 )
199         EXIT;
200
201     // calculate the normalizing transformations for each of the point sets:
202     // after the transformation each set will have the mass center at the coordinate origin
203     // and the average distance from the origin will be ~sqrt(2).
204     t = 1./good_count;
205     m0c.x *= t; m0c.y *= t;
206     m1c.x *= t; m1c.y *= t;
207
208     for( i = 0; i < count; i++ )
209         if( !mask || mask[i] )
210         {
211             double x = m0[i].x - m0c.x, y = m0[i].y - m0c.y;
212             scale0 += sqrt(x*x + y*y);
213
214             x = fabs(m1[i].x - m1c.x), y = fabs(m1[i].y - m1c.y);
215             scale1 += sqrt(x*x + y*y);
216         }
217
218     scale0 *= t;
219     scale1 *= t;
220
221     if( scale0 < FLT_EPSILON || scale1 < FLT_EPSILON )
222         EXIT;
223
224     scale0 = sqrt(2.)/scale0;
225     scale1 = sqrt(2.)/scale1;
226
227     CV_CALL( A = cvCreateMat( good_count, 9, CV_64F ));
228     a = A->data.db;
229     a_step = A->step / sizeof(a[0]);
230
231     // form a linear system: for each selected pair of points m0 & m1,
232     // the row of A(=a) represents the equation: (m1, 1)'*F*(m0, 1) = 0
233     for( i = 0; i < count; i++ )
234     {
235         if( !mask || mask[i] )
236         {
237             double x0 = (m0[i].x - m0c.x)*scale0;
238             double y0 = (m0[i].y - m0c.y)*scale0;
239             double x1 = (m1[i].x - m1c.x)*scale1;
240             double y1 = (m1[i].y - m1c.y)*scale1;
241
242             a[0] = x1*x0;
243             a[1] = x1*y0;
244             a[2] = x1;
245             a[3] = y1*x0;
246             a[4] = y1*y0;
247             a[5] = y1;
248             a[6] = x0;
249             a[7] = y0;
250             a[8] = 1;
251             a += a_step;
252         }
253     }
254
255     cvSVD( A, &W, 0, &V, CV_SVD_MODIFY_A + CV_SVD_V_T );
256
257     for( i = 0; i < 8; i++ )
258     {
259         if( fabs(w[i]) < FLT_EPSILON )
260             break;
261     }
262
263     if( i < 7 )
264         EXIT;
265
266     F0 = cvMat( 3, 3, CV_64F, v + 9*8 ); // take the last column of v as a solution of Af = 0
267
268     // make F0 singular (of rank 2) by decomposing it with SVD,
269     // zeroing the last diagonal element of W and then composing the matrices back.
270
271     // use v as a temporary storage for different 3x3 matrices
272     W = U = V = TF = F0;
273     W.data.db = v;
274     U.data.db = v + 9;
275     V.data.db = v + 18;
276     TF.data.db = v + 27;
277
278     cvSVD( &F0, &W, &U, &V, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
279     W.data.db[8] = 0.;
280
281     // F0 <- U*diag([W(1), W(2), 0])*V'
282     cvGEMM( &U, &W, 1., 0, 0., &TF, CV_GEMM_A_T );
283     cvGEMM( &TF, &V, 1., 0, 0., &F0, 0/*CV_GEMM_B_T*/ );
284
285     // apply the transformation that is inverse
286     // to what we used to normalize the point coordinates
287     {
288         double tt0[] = { scale0, 0, -scale0*m0c.x, 0, scale0, -scale0*m0c.y, 0, 0, 1 };
289         double tt1[] = { scale1, 0, -scale1*m1c.x, 0, scale1, -scale1*m1c.y, 0, 0, 1 };
290         CvMat T0, T1;
291         T0 = T1 = F0;
292         T0.data.db = tt0;
293         T1.data.db = tt1;
294
295         // F0 <- T1'*F0*T0
296         cvGEMM( &T1, &F0, 1., 0, 0., &TF, CV_GEMM_A_T );
297         F0.data.db = fmatrix;
298         cvGEMM( &TF, &T0, 1., 0, 0., &F0, 0 );
299
300         // make F(3,3) = 1
301         if( fabs(F0.data.db[8]) > FLT_EPSILON )
302             cvScale( &F0, &F0, 1./F0.data.db[8] );
303     }
304
305     result = 1;
306
307     __END__;
308
309     cvReleaseMat( &A );
310     return result;
311 }
312
313
314 CV_IMPL int
315 cvRANSACUpdateNumIters( double p, double ep,
316                         int model_points, int max_iters )
317 {
318     int result = 0;
319     
320     CV_FUNCNAME( "cvRANSACUpdateNumIters" );
321
322     __BEGIN__;
323     
324     double num, denom;
325     
326     if( model_points <= 0 )
327         CV_ERROR( CV_StsOutOfRange, "the number of model points should be positive" );
328
329     p = MAX(p, 0.);
330     p = MIN(p, 1.);
331     ep = MAX(ep, 0.);
332     ep = MIN(ep, 1.);
333
334     // avoid inf's & nan's
335     num = MAX(1. - p, DBL_MIN);
336     denom = 1. - pow(1. - ep,model_points);
337     if( denom < DBL_MIN )
338         EXIT;
339
340     num = log(num);
341     denom = log(denom);
342     
343     result = denom >= 0 || -num >= max_iters*(-denom) ?
344         max_iters : cvRound(num/denom);
345
346     __END__;
347
348     return result;
349 }
350
351
352 /************************************ RANSAC algorithm **********************************/
353 static int
354 icvFMatrix_RANSAC( const CvPoint2D64f* m0, const CvPoint2D64f* m1,
355                    uchar* mask, int count, double* fmatrix,
356                    double threshold, double p,
357                    unsigned rng_seed, int use_8point )
358 {
359     int result = 0;
360
361     const int max_random_iters = 1000;
362     const int sample_size = 7;
363     uchar* curr_mask = 0;
364     uchar* temp_mask = 0;
365
366     CV_FUNCNAME( "icvFMatrix_RANSAC" );
367
368     __BEGIN__;
369
370     double ff[9*3];
371     CvRNG rng = cvRNG(rng_seed);
372     int i, j, k, sample_count, max_samples = 500;
373     int best_good_count = 0;
374
375     assert( m0 && m1 && fmatrix && 0 < p && p < 1 && threshold > 0 );
376
377     threshold *= threshold;
378
379     CV_CALL( curr_mask = (uchar*)cvAlloc( count ));
380     if( !mask && use_8point )
381     {
382         CV_CALL( temp_mask = (uchar*)cvAlloc( count ));
383         mask = temp_mask;
384     }
385
386     // find the best fundamental matrix (giving the least backprojection error)
387     // by picking at most <max_samples> 7-tuples of corresponding points
388     // <max_samples> may be updated (decreased) within the loop based on statistics of outliers
389     for( sample_count = 0; sample_count < max_samples; sample_count++ )
390     {
391         int idx[sample_size], n;
392         CvPoint2D64f ms0[sample_size], ms1[sample_size];
393
394         // choose random <sample_size> (=7) points
395         for( i = 0; i < sample_size; i++ )
396         {
397             for( k = 0; k < max_random_iters; k++ )
398             {
399                 idx[i] = cvRandInt(&rng) % count;
400                 for( j = 0; j < i; j++ )
401                     if( idx[j] == idx[i] )
402                         break;
403                 if( j == i )
404                 {
405                     ms0[i] = m0[idx[i]];
406                     ms1[i] = m1[idx[i]];
407                     break;
408                 }
409             }
410             if( k >= max_random_iters )
411                 break;
412         }
413
414         if( i < sample_size )
415             continue;
416
417         // find 1 or 3 fundamental matrices out of the 7 point correspondences
418         n = icvFMatrix_7Point( ms0, ms1, ff );
419
420         if( n < 1 || n > 3 )
421             continue;
422
423         // for each matrix calculate the backprojection error
424         // (distance to the corresponding epipolar lines) for each point and thus find
425         // the number of in-liers.
426         for( k = 0; k < n; k++ )
427         {
428             const double* f = ff + k*9;
429             int good_count = 0;
430
431             for( i = 0; i < count; i++ )
432             {
433                 double d0, d1, s0, s1;
434
435                 double a = f[0]*m0[i].x + f[1]*m0[i].y + f[2];
436                 double b = f[3]*m0[i].x + f[4]*m0[i].y + f[5];
437                 double c = f[6]*m0[i].x + f[7]*m0[i].y + f[8];
438
439                 s1 = a*a + b*b;
440                 d1 = m1[i].x*a + m1[i].y*b + c;
441
442                 a = f[0]*m1[i].x + f[3]*m1[i].y + f[6];
443                 b = f[1]*m1[i].x + f[4]*m1[i].y + f[7];
444                 c = f[2]*m1[i].x + f[5]*m1[i].y + f[8];
445
446                 s0 = a*a + b*b;
447                 d0 = m0[i].x*a + m0[i].y*b + c;
448
449                 curr_mask[i] = d1*d1 < threshold*s1 && d0*d0 < threshold*s0;
450                 good_count += curr_mask[i];
451             }
452
453             if( good_count > MAX( best_good_count, 6 ) )
454             {
455                 // update the current best fundamental matrix and "goodness" flags
456                 if( mask )
457                     memcpy( mask, curr_mask, count );
458                 memcpy( fmatrix, f, 9*sizeof(f[0]));
459                 best_good_count = good_count;
460                 
461                 max_samples = cvRANSACUpdateNumIters( p,
462                     (double)(count - good_count)/count, 7, max_samples );
463                 if( max_samples == 0 )
464                     break;
465             }
466         }
467     }
468
469     if( best_good_count < 7 )
470         EXIT;
471
472     result = 1;
473
474     // optionally, use 8-point algorithm to compute fundamental matrix using only the in-liers
475     if( best_good_count >= 8 && use_8point )
476         result = icvFMatrix_8Point( m0, m1, mask, count, fmatrix );
477
478     __END__;
479
480     cvFree( &temp_mask );
481     cvFree( &curr_mask );
482
483     return result;
484 }
485
486
487 /***************************** Least Median of Squares algorithm ************************/
488
489 static CV_IMPLEMENT_QSORT( icvSortDistances, int, CV_LT )
490
491 /* the algorithm is quite similar to RANSAC, but here we choose the matrix that gives
492    the least median of d(m0[i], F'*m1[i])^2 + d(m1[i], F*m0[i])^2 (0<=i<count),
493    instead of choosing the matrix that gives the least number of outliers (as it is done in RANSAC) */
494 static int
495 icvFMatrix_LMedS( const CvPoint2D64f* m0, const CvPoint2D64f* m1,
496                   uchar* mask, int count, double* fmatrix,
497                   double threshold, double p,
498                   unsigned rng_seed, int use_8point )
499 {
500     int result = 0;
501
502     const int max_random_iters = 1000;
503     const int sample_size = 7;
504
505     float* dist = 0;
506     uchar* curr_mask = 0;
507     uchar* temp_mask = 0;
508
509     CV_FUNCNAME( "icvFMatrix_LMedS" );
510
511     __BEGIN__;
512
513     double ff[9*3];
514     CvRNG rng = cvRNG(rng_seed);
515     int i, j, k, sample_count, max_samples = 500;
516     double least_median = DBL_MAX, median;
517     int best_good_count = 0;
518
519     assert( m0 && m1 && fmatrix && 0 < p && p < 1 && threshold > 0 );
520
521     threshold *= threshold;
522
523     CV_CALL( curr_mask = (uchar*)cvAlloc( count ));
524     CV_CALL( dist = (float*)cvAlloc( count*sizeof(dist[0]) ));
525
526     if( !mask && use_8point )
527     {
528         CV_CALL( temp_mask = (uchar*)cvAlloc( count ));
529         mask = temp_mask;
530     }
531
532     // find the best fundamental matrix (giving the least backprojection error)
533     // by picking at most <max_samples> 7-tuples of corresponding points
534     // <max_samples> may be updated (decreased) within the loop based on statistics of outliers
535     for( sample_count = 0; sample_count < max_samples; sample_count++ )
536     {
537         int idx[sample_size], n;
538         CvPoint2D64f ms0[sample_size], ms1[sample_size];
539
540         // choose random <sample_size> (=7) points
541         for( i = 0; i < sample_size; i++ )
542         {
543             for( k = 0; k < max_random_iters; k++ )
544             {
545                 idx[i] = cvRandInt(&rng) % count;
546                 for( j = 0; j < i; j++ )
547                     if( idx[j] == idx[i] )
548                         break;
549                 if( j == i )
550                 {
551                     ms0[i] = m0[idx[i]];
552                     ms1[i] = m1[idx[i]];
553                     break;
554                 }
555             }
556             if( k >= max_random_iters )
557                 break;
558         }
559
560         if( i < sample_size )
561             continue;
562
563         // find 1 or 3 fundamental matrix out of the 7 point correspondences
564         n = icvFMatrix_7Point( ms0, ms1, ff );
565
566         if( n < 1 || n > 3 )
567             continue;
568
569         // for each matrix calculate the backprojection error
570         // (distance to the corresponding epipolar lines) for each point and thus find
571         // the number of in-liers.
572         for( k = 0; k < n; k++ )
573         {
574             const double* f = ff + k*9;
575             int good_count = 0;
576
577             for( i = 0; i < count; i++ )
578             {
579                 double d0, d1, s;
580
581                 double a = f[0]*m0[i].x + f[1]*m0[i].y + f[2];
582                 double b = f[3]*m0[i].x + f[4]*m0[i].y + f[5];
583                 double c = f[6]*m0[i].x + f[7]*m0[i].y + f[8];
584
585                 s = 1./(a*a + b*b);
586                 d1 = m1[i].x*a + m1[i].y*b + c;
587                 d1 = s*d1*d1;
588
589                 a = f[0]*m1[i].x + f[3]*m1[i].y + f[6];
590                 b = f[1]*m1[i].x + f[4]*m1[i].y + f[7];
591                 c = f[2]*m1[i].x + f[5]*m1[i].y + f[8];
592
593                 s = 1./(a*a + b*b);
594                 d0 = m0[i].x*a + m0[i].y*b + c;
595                 d0 = s*d0*d0;
596
597                 curr_mask[i] = d1 < threshold && d0 < threshold;
598                 good_count += curr_mask[i];
599
600                 dist[i] = (float)(d0 + d1);
601             }
602
603             icvSortDistances( (int*)dist, count, 0 );
604             median = (double)dist[count/2];
605
606             if( median < least_median )
607             {
608                 double ep, lp, lep;
609                 int new_max_samples;
610
611                 // update the current best fundamental matrix and "goodness" flags
612                 if( mask )
613                     memcpy( mask, curr_mask, count );
614                 memcpy( fmatrix, f, 9*sizeof(f[0]));
615                 least_median = median;
616                 best_good_count = good_count;
617
618                 // try to update (decrease) <max_samples>
619                 ep = (double)(count - good_count)/count;
620                 lp = log(1. - p);
621                 lep = log(1. - pow(ep,7.));
622                 if( lp < lep || lep >= 0 )
623                     break;
624                 else
625                 {
626                     new_max_samples = cvRound(lp/lep);
627                     max_samples = MIN( new_max_samples, max_samples );
628                 }
629             }
630         }
631     }
632
633     if( best_good_count < 7 )
634         EXIT;
635
636     result = 1;
637
638     // optionally, use 8-point algorithm to compute fundamental matrix using only the in-liers
639     if( best_good_count >= 8 && use_8point )
640         result = icvFMatrix_8Point( m0, m1, mask, count, fmatrix );
641
642     __END__;
643
644     cvFree( &temp_mask );
645     cvFree( &curr_mask );
646     cvFree( &dist );
647
648     return result;
649 }
650
651
652 CV_IMPL int
653 cvFindFundamentalMat( const CvMat* points0, const CvMat* points1,
654                       CvMat* fmatrix, int method,
655                       double param1, double param2, CvMat* status )
656 {
657     const unsigned rng_seed = 0xffffffff;
658     int result = 0;
659     int pt_alloc_flag[2] = { 0, 0 };
660     int i, k;
661     CvPoint2D64f* pt[2] = { 0, 0 };
662     CvMat* _status = 0;
663
664     CV_FUNCNAME( "cvFindFundamentalMat" );
665
666     __BEGIN__;
667
668     int count, dims;
669     int depth, cn;
670     uchar* status_data = 0;
671     double fmatrix_data0[9*3];
672     double* fmatrix_data = 0;
673
674     if( !CV_IS_MAT(points0) )
675         CV_ERROR( !points0 ? CV_StsNullPtr : CV_StsBadArg, "points0 is not a valid matrix" );
676
677     if( !CV_IS_MAT(points1) )
678         CV_ERROR( !points1 ? CV_StsNullPtr : CV_StsBadArg, "points1 is not a valid matrix" );
679
680     if( !CV_ARE_TYPES_EQ(points0, points1) )
681         CV_ERROR( CV_StsUnmatchedFormats, "The matrices of points should have the same data type" );
682
683     if( !CV_ARE_SIZES_EQ(points0, points1) )
684         CV_ERROR( CV_StsUnmatchedSizes, "The matrices of points should have the same size" );
685
686     depth = CV_MAT_DEPTH(points0->type);
687     cn = CV_MAT_CN(points0->type);
688     if( depth != CV_32S && depth != CV_32F && depth != CV_64F || cn != 1 && cn != 2 && cn != 3 )
689         CV_ERROR( CV_StsUnsupportedFormat, "The format of point matrices is unsupported" );
690
691     if( points0->rows > points0->cols )
692     {
693         dims = cn*points0->cols;
694         count = points0->rows;
695     }
696     else
697     {
698         if( points0->rows > 1 && cn > 1 || points0->rows == 1 && cn == 1 )
699             CV_ERROR( CV_StsBadSize, "The point matrices do not have a proper layout (2xn, 3xn, nx2 or nx3)" );
700         dims = cn * points0->rows;
701         count = points0->cols;
702     }
703
704     if( dims != 2 && dims != 3 )
705         CV_ERROR( CV_StsOutOfRange, "The dimensionality of points must be 2 or 3" );
706
707     if( method == CV_FM_7POINT && count != 7 ||
708         method != CV_FM_7POINT && count < 7 + (method == CV_FM_8POINT) )
709         CV_ERROR( CV_StsOutOfRange,
710         "The number of points must be 7 for 7-point algorithm, "
711         ">=8 for 8-point algorithm and >=7 for other algorithms" );
712
713     if( !CV_IS_MAT(fmatrix) )
714         CV_ERROR( !fmatrix ? CV_StsNullPtr : CV_StsBadArg, "fmatrix is not a valid matrix" );
715
716     if( CV_MAT_TYPE(fmatrix->type) != CV_32FC1 && CV_MAT_TYPE(fmatrix->type) != CV_64FC1 )
717         CV_ERROR( CV_StsUnsupportedFormat, "fundamental matrix must have 32fC1 or 64fC1 type" );
718
719     if( fmatrix->cols != 3 || (fmatrix->rows != 3 && (method != CV_FM_7POINT || fmatrix->rows != 9)))
720         CV_ERROR( CV_StsBadSize, "fundamental matrix must be 3x3 or 3x9 (for 7-point method only)" );
721
722     fmatrix_data = fmatrix->data.db;
723     if( !CV_IS_MAT_CONT(fmatrix->type) || CV_MAT_TYPE(fmatrix->type) != CV_64FC1 ||
724         method == CV_FM_7POINT && fmatrix->rows != 9 )
725         fmatrix_data = fmatrix_data0;
726
727     if( status )
728     {
729         if( !CV_IS_MAT(status) )
730             CV_ERROR( CV_StsBadArg, "The output status is not a valid matrix" );
731
732         if( status->cols != 1 && status->rows != 1 || status->cols + status->rows - 1 != count )
733             CV_ERROR( CV_StsUnmatchedSizes,
734             "The status matrix must have the same size as the point matrices" );
735
736         if( method == CV_FM_7POINT || method == CV_FM_8POINT )
737             cvSet( status, cvScalarAll(1.) );
738         else
739         {
740             status_data = status->data.ptr;
741             if( !CV_IS_MAT_CONT(status->type) || !CV_IS_MASK_ARR(status) )
742             {
743                 CV_CALL( _status = cvCreateMat( status->rows, status->cols, CV_8UC1 ));
744                 status_data = _status->data.ptr;
745             }
746         }
747     }
748
749     for( k = 0; k < 2; k++ )
750     {
751         const CvMat* spt = k == 0 ? points0 : points1;
752         CvPoint2D64f* dpt = pt[k] = (CvPoint2D64f*)spt->data.db;
753         int plane_stride, stride, elem_size;
754
755         if( CV_IS_MAT_CONT(spt->type) && CV_MAT_DEPTH(spt->type) == CV_64F &&
756             dims == 2 && (spt->rows == 1 || spt->rows == count) )
757             continue;
758
759         elem_size = CV_ELEM_SIZE(depth);
760
761         if( spt->rows == dims )
762         {
763             plane_stride = spt->step / elem_size;
764             stride = 1;
765         }
766         else
767         {
768             plane_stride = 1;
769             stride = spt->rows == 1 ? dims : spt->step / elem_size;
770         }
771
772         CV_CALL( dpt = pt[k] = (CvPoint2D64f*)cvAlloc( count*sizeof(dpt[0]) ));
773         pt_alloc_flag[k] = 1;
774
775         if( depth == CV_32F )
776         {
777             const float* xp = spt->data.fl;
778             const float* yp = xp + plane_stride;
779             const float* zp = dims == 3 ? yp + plane_stride : 0;
780
781             for( i = 0; i < count; i++ )
782             {
783                 double x = *xp, y = *yp;
784                 xp += stride;
785                 yp += stride;
786                 if( dims == 3 )
787                 {
788                     double z = *zp;
789                     zp += stride;
790                     z = z ? 1./z : 1.;
791                     x *= z;
792                     y *= z;
793                 }
794                 dpt[i].x = x;
795                 dpt[i].y = y;
796             }
797         }
798         else
799         {
800             const double* xp = spt->data.db;
801             const double* yp = xp + plane_stride;
802             const double* zp = dims == 3 ? yp + plane_stride : 0;
803
804             for( i = 0; i < count; i++ )
805             {
806                 double x = *xp, y = *yp;
807                 xp += stride;
808                 yp += stride;
809                 if( dims == 3 )
810                 {
811                     double z = *zp;
812                     zp += stride;
813                     z = z ? 1./z : 1.;
814                     x *= z;
815                     y *= z;
816                 }
817                 dpt[i].x = x;
818                 dpt[i].y = y;
819             }
820         }
821     }
822
823     if( method == CV_FM_7POINT )
824         result = icvFMatrix_7Point( pt[0], pt[1], fmatrix_data );
825     else if( method == CV_FM_8POINT )
826         result = icvFMatrix_8Point( pt[0], pt[1], 0, count, fmatrix_data );
827     else
828     {
829         if( param1 < 0 )
830             CV_ERROR( CV_StsOutOfRange, "param1 (threshold) must be > 0" );
831
832         if( param2 < 0 || param2 > 1 )
833             CV_ERROR( CV_StsOutOfRange, "param2 (confidence level) must be between 0 and 1" );
834
835         if( param2 < DBL_EPSILON || param2 > 1 - DBL_EPSILON )
836             param2 = 0.99;
837
838         if( method < CV_FM_RANSAC_ONLY )
839             result = icvFMatrix_LMedS( pt[0], pt[1], status_data, count, fmatrix_data,
840                                        param1, param2, rng_seed, method & CV_FM_8POINT );
841         else
842             result = icvFMatrix_RANSAC( pt[0], pt[1], status_data, count, fmatrix_data,
843                                         param1, param2, rng_seed, method & CV_FM_8POINT );
844     }
845
846     if( result && fmatrix->data.db != fmatrix_data )
847     {
848         CvMat hdr;
849         cvZero( fmatrix );
850         hdr = cvMat( MIN(fmatrix->rows, result*3), fmatrix->cols, CV_64F, fmatrix_data );
851         cvConvert( &hdr, fmatrix );
852     }
853
854     if( status && status_data && status->data.ptr != status_data )
855         cvConvert( _status, status );
856
857     __END__;
858
859     cvReleaseMat( &_status );
860     for( k = 0; k < 2; k++ )
861         if( pt_alloc_flag[k] )
862             cvFree( &pt[k] );
863
864     return result;
865 }
866
867
868 CV_IMPL void
869 cvComputeCorrespondEpilines( const CvMat* points, int pointImageID,
870                              const CvMat* fmatrix, CvMat* lines )
871 {
872     CV_FUNCNAME( "cvComputeCorrespondEpilines" );
873
874     __BEGIN__;
875
876     int abc_stride, abc_plane_stride, abc_elem_size;
877     int plane_stride, stride, elem_size;
878     int i, dims, count, depth, cn, abc_dims, abc_count, abc_depth, abc_cn;
879     uchar *ap, *bp, *cp;
880     const uchar *xp, *yp, *zp;
881     double f[9];
882     CvMat F = cvMat( 3, 3, CV_64F, f );
883
884     if( !CV_IS_MAT(points) )
885         CV_ERROR( !points ? CV_StsNullPtr : CV_StsBadArg, "points parameter is not a valid matrix" );
886
887     depth = CV_MAT_DEPTH(points->type);
888     cn = CV_MAT_CN(points->type);
889     if( depth != CV_32F && depth != CV_64F || cn != 1 && cn != 2 && cn != 3 )
890         CV_ERROR( CV_StsUnsupportedFormat, "The format of point matrix is unsupported" );
891
892     if( points->rows > points->cols )
893     {
894         dims = cn*points->cols;
895         count = points->rows;
896     }
897     else
898     {
899         if( points->rows > 1 && cn > 1 || points->rows == 1 && cn == 1 )
900             CV_ERROR( CV_StsBadSize, "The point matrix does not have a proper layout (2xn, 3xn, nx2 or nx3)" );
901         dims = cn * points->rows;
902         count = points->cols;
903     }
904
905     if( dims != 2 && dims != 3 )
906         CV_ERROR( CV_StsOutOfRange, "The dimensionality of points must be 2 or 3" );
907
908     if( !CV_IS_MAT(fmatrix) )
909         CV_ERROR( !fmatrix ? CV_StsNullPtr : CV_StsBadArg, "fmatrix is not a valid matrix" );
910
911     if( CV_MAT_TYPE(fmatrix->type) != CV_32FC1 && CV_MAT_TYPE(fmatrix->type) != CV_64FC1 )
912         CV_ERROR( CV_StsUnsupportedFormat, "fundamental matrix must have 32fC1 or 64fC1 type" );
913
914     if( fmatrix->cols != 3 || fmatrix->rows != 3 )
915         CV_ERROR( CV_StsBadSize, "fundamental matrix must be 3x3" );
916
917     if( !CV_IS_MAT(lines) )
918         CV_ERROR( !lines ? CV_StsNullPtr : CV_StsBadArg, "lines parameter is not a valid matrix" );
919
920     abc_depth = CV_MAT_DEPTH(lines->type);
921     abc_cn = CV_MAT_CN(lines->type);
922     if( abc_depth != CV_32F && abc_depth != CV_64F || abc_cn != 1 && abc_cn != 3 )
923         CV_ERROR( CV_StsUnsupportedFormat, "The format of the matrix of lines is unsupported" );
924
925     if( lines->rows > lines->cols )
926     {
927         abc_dims = abc_cn*lines->cols;
928         abc_count = lines->rows;
929     }
930     else
931     {
932         if( lines->rows > 1 && abc_cn > 1 || lines->rows == 1 && abc_cn == 1 )
933             CV_ERROR( CV_StsBadSize, "The lines matrix does not have a proper layout (3xn or nx3)" );
934         abc_dims = abc_cn * lines->rows;
935         abc_count = lines->cols;
936     }
937
938     if( abc_dims != 3 )
939         CV_ERROR( CV_StsOutOfRange, "The lines matrix does not have a proper layout (3xn or nx3)" );
940
941     if( abc_count != count )
942         CV_ERROR( CV_StsUnmatchedSizes, "The numbers of points and lines are different" );
943
944     elem_size = CV_ELEM_SIZE(depth);
945     abc_elem_size = CV_ELEM_SIZE(abc_depth);
946
947     if( points->rows == dims )
948     {
949         plane_stride = points->step;
950         stride = elem_size;
951     }
952     else
953     {
954         plane_stride = elem_size;
955         stride = points->rows == 1 ? dims*elem_size : points->step;
956     }
957
958     if( lines->rows == 3 )
959     {
960         abc_plane_stride = lines->step;
961         abc_stride = abc_elem_size;
962     }
963     else
964     {
965         abc_plane_stride = abc_elem_size;
966         abc_stride = lines->rows == 1 ? 3*abc_elem_size : lines->step;
967     }
968
969     CV_CALL( cvConvert( fmatrix, &F ));
970     if( pointImageID == 2 )
971         cvTranspose( &F, &F );
972
973     xp = points->data.ptr;
974     yp = xp + plane_stride;
975     zp = dims == 3 ? yp + plane_stride : 0;
976
977     ap = lines->data.ptr;
978     bp = ap + abc_plane_stride;
979     cp = bp + abc_plane_stride;
980
981     for( i = 0; i < count; i++ )
982     {
983         double x, y, z = 1.;
984         double a, b, c, nu;
985
986         if( depth == CV_32F )
987         {
988             x = *(float*)xp; y = *(float*)yp;
989             if( zp )
990                 z = *(float*)zp, zp += stride;
991         }
992         else
993         {
994             x = *(double*)xp; y = *(double*)yp;
995             if( zp )
996                 z = *(double*)zp, zp += stride;
997         }
998
999         xp += stride; yp += stride;
1000
1001         a = f[0]*x + f[1]*y + f[2]*z;
1002         b = f[3]*x + f[4]*y + f[5]*z;
1003         c = f[6]*x + f[7]*y + f[8]*z;
1004         nu = a*a + b*b;
1005         nu = nu ? 1./sqrt(nu) : 1.;
1006         a *= nu; b *= nu; c *= nu;
1007
1008         if( abc_depth == CV_32F )
1009         {
1010             *(float*)ap = (float)a;
1011             *(float*)bp = (float)b;
1012             *(float*)cp = (float)c;
1013         }
1014         else
1015         {
1016             *(double*)ap = a;
1017             *(double*)bp = b;
1018             *(double*)cp = c;
1019         }
1020
1021         ap += abc_stride;
1022         bp += abc_stride;
1023         cp += abc_stride;
1024     }
1025
1026     __END__;
1027 }
1028
1029
1030 CV_IMPL void
1031 cvConvertPointsHomogenious( const CvMat* src, CvMat* dst )
1032 {
1033     CvMat* temp = 0;
1034     CvMat* denom = 0;
1035
1036     CV_FUNCNAME( "cvConvertPointsHomogenious" );
1037
1038     __BEGIN__;
1039
1040     int i, s_count, s_dims, d_count, d_dims;
1041     CvMat _src, _dst, _ones;
1042     CvMat* ones = 0;
1043
1044     if( !CV_IS_MAT(src) )
1045         CV_ERROR( !src ? CV_StsNullPtr : CV_StsBadArg,
1046         "The input parameter is not a valid matrix" );
1047
1048     if( !CV_IS_MAT(dst) )
1049         CV_ERROR( !dst ? CV_StsNullPtr : CV_StsBadArg,
1050         "The output parameter is not a valid matrix" );
1051
1052     if( src == dst || src->data.ptr == dst->data.ptr )
1053     {
1054         if( src != dst && (!CV_ARE_TYPES_EQ(src, dst) || !CV_ARE_SIZES_EQ(src,dst)) )
1055             CV_ERROR( CV_StsBadArg, "Invalid inplace operation" );
1056         EXIT;
1057     }
1058
1059     if( src->rows > src->cols )
1060     {
1061         if( !((src->cols > 1) ^ (CV_MAT_CN(src->type) > 1)) )
1062             CV_ERROR( CV_StsBadSize, "Either the number of channels or columns or rows must be =1" );
1063
1064         s_dims = CV_MAT_CN(src->type)*src->cols;
1065         s_count = src->rows;
1066     }
1067     else
1068     {
1069         if( !((src->rows > 1) ^ (CV_MAT_CN(src->type) > 1)) )
1070             CV_ERROR( CV_StsBadSize, "Either the number of channels or columns or rows must be =1" );
1071
1072         s_dims = CV_MAT_CN(src->type)*src->rows;
1073         s_count = src->cols;
1074     }
1075
1076     if( src->rows == 1 || src->cols == 1 )
1077         src = cvReshape( src, &_src, 1, s_count );
1078
1079     if( dst->rows > dst->cols )
1080     {
1081         if( !((dst->cols > 1) ^ (CV_MAT_CN(dst->type) > 1)) )
1082             CV_ERROR( CV_StsBadSize,
1083             "Either the number of channels or columns or rows in the input matrix must be =1" );
1084
1085         d_dims = CV_MAT_CN(dst->type)*dst->cols;
1086         d_count = dst->rows;
1087     }
1088     else
1089     {
1090         if( !((dst->rows > 1) ^ (CV_MAT_CN(dst->type) > 1)) )
1091             CV_ERROR( CV_StsBadSize,
1092             "Either the number of channels or columns or rows in the output matrix must be =1" );
1093
1094         d_dims = CV_MAT_CN(dst->type)*dst->rows;
1095         d_count = dst->cols;
1096     }
1097
1098     if( dst->rows == 1 || dst->cols == 1 )
1099         dst = cvReshape( dst, &_dst, 1, d_count );
1100
1101     if( s_count != d_count )
1102         CV_ERROR( CV_StsUnmatchedSizes, "Both matrices must have the same number of points" );
1103
1104     if( CV_MAT_DEPTH(src->type) < CV_32F || CV_MAT_DEPTH(dst->type) < CV_32F )
1105         CV_ERROR( CV_StsUnsupportedFormat,
1106         "Both matrices must be floating-point (single or double precision)" );
1107
1108     if( s_dims < 2 || s_dims > 4 || d_dims < 2 || d_dims > 4 )
1109         CV_ERROR( CV_StsOutOfRange,
1110         "Both input and output point dimensionality must be 2, 3 or 4" );
1111
1112     if( s_dims < d_dims - 1 || s_dims > d_dims + 1 )
1113         CV_ERROR( CV_StsUnmatchedSizes,
1114         "The dimensionalities of input and output point sets differ too much" );
1115
1116     if( s_dims == d_dims - 1 )
1117     {
1118         if( d_count == dst->rows )
1119         {
1120             ones = cvGetSubRect( dst, &_ones, cvRect( s_dims, 0, 1, d_count ));
1121             dst = cvGetSubRect( dst, &_dst, cvRect( 0, 0, s_dims, d_count ));
1122         }
1123         else
1124         {
1125             ones = cvGetSubRect( dst, &_ones, cvRect( 0, s_dims, d_count, 1 ));
1126             dst = cvGetSubRect( dst, &_dst, cvRect( 0, 0, d_count, s_dims ));
1127         }
1128     }
1129
1130     if( s_dims <= d_dims )
1131     {
1132         if( src->rows == dst->rows && src->cols == dst->cols )
1133         {
1134             if( CV_ARE_TYPES_EQ( src, dst ) )
1135                 cvCopy( src, dst );
1136             else
1137                 cvConvert( src, dst );
1138         }
1139         else
1140         {
1141             if( !CV_ARE_TYPES_EQ( src, dst ))
1142             {
1143                 CV_CALL( temp = cvCreateMat( src->rows, src->cols, dst->type ));
1144                 cvConvert( src, temp );
1145                 src = temp;
1146             }
1147             cvTranspose( src, dst );
1148         }
1149
1150         if( ones )
1151             cvSet( ones, cvRealScalar(1.) );
1152     }
1153     else
1154     {
1155         int s_plane_stride, s_stride, d_plane_stride, d_stride, elem_size;
1156
1157         if( !CV_ARE_TYPES_EQ( src, dst ))
1158         {
1159             CV_CALL( temp = cvCreateMat( src->rows, src->cols, dst->type ));
1160             cvConvert( src, temp );
1161             src = temp;
1162         }
1163
1164         elem_size = CV_ELEM_SIZE(src->type);
1165
1166         if( s_count == src->cols )
1167             s_plane_stride = src->step / elem_size, s_stride = 1;
1168         else
1169             s_stride = src->step / elem_size, s_plane_stride = 1;
1170
1171         if( d_count == dst->cols )
1172             d_plane_stride = dst->step / elem_size, d_stride = 1;
1173         else
1174             d_stride = dst->step / elem_size, d_plane_stride = 1;
1175
1176         CV_CALL( denom = cvCreateMat( 1, d_count, dst->type ));
1177
1178         if( CV_MAT_DEPTH(dst->type) == CV_32F )
1179         {
1180             const float* xs = src->data.fl;
1181             const float* ys = xs + s_plane_stride;
1182             const float* zs = 0;
1183             const float* ws = xs + (s_dims - 1)*s_plane_stride;
1184
1185             float* iw = denom->data.fl;
1186
1187             float* xd = dst->data.fl;
1188             float* yd = xd + d_plane_stride;
1189             float* zd = 0;
1190
1191             if( d_dims == 3 )
1192             {
1193                 zs = ys + s_plane_stride;
1194                 zd = yd + d_plane_stride;
1195             }
1196
1197             for( i = 0; i < d_count; i++, ws += s_stride )
1198             {
1199                 float t = *ws;
1200                 iw[i] = t ? t : 1.f;
1201             }
1202
1203             cvDiv( 0, denom, denom );
1204
1205             if( d_dims == 3 )
1206                 for( i = 0; i < d_count; i++ )
1207                 {
1208                     float w = iw[i];
1209                     float x = *xs * w, y = *ys * w, z = *zs * w;
1210                     xs += s_stride; ys += s_stride; zs += s_stride;
1211                     *xd = x; *yd = y; *zd = z;
1212                     xd += d_stride; yd += d_stride; zd += d_stride;
1213                 }
1214             else
1215                 for( i = 0; i < d_count; i++ )
1216                 {
1217                     float w = iw[i];
1218                     float x = *xs * w, y = *ys * w;
1219                     xs += s_stride; ys += s_stride;
1220                     *xd = x; *yd = y;
1221                     xd += d_stride; yd += d_stride;
1222                 }
1223         }
1224         else
1225         {
1226             const double* xs = src->data.db;
1227             const double* ys = xs + s_plane_stride;
1228             const double* zs = 0;
1229             const double* ws = xs + (s_dims - 1)*s_plane_stride;
1230
1231             double* iw = denom->data.db;
1232
1233             double* xd = dst->data.db;
1234             double* yd = xd + d_plane_stride;
1235             double* zd = 0;
1236
1237             if( d_dims == 3 )
1238             {
1239                 zs = ys + s_plane_stride;
1240                 zd = yd + d_plane_stride;
1241             }
1242
1243             for( i = 0; i < d_count; i++, ws += s_stride )
1244             {
1245                 double t = *ws;
1246                 iw[i] = t ? t : 1.;
1247             }
1248
1249             cvDiv( 0, denom, denom );
1250
1251             if( d_dims == 3 )
1252                 for( i = 0; i < d_count; i++ )
1253                 {
1254                     double w = iw[i];
1255                     double x = *xs * w, y = *ys * w, z = *zs * w;
1256                     xs += s_stride; ys += s_stride; zs += s_stride;
1257                     *xd = x; *yd = y; *zd = z;
1258                     xd += d_stride; yd += d_stride; zd += d_stride;
1259                 }
1260             else
1261                 for( i = 0; i < d_count; i++ )
1262                 {
1263                     double w = iw[i];
1264                     double x = *xs * w, y = *ys * w;
1265                     xs += s_stride; ys += s_stride;
1266                     *xd = x; *yd = y;
1267                     xd += d_stride; yd += d_stride;
1268                 }
1269         }
1270     }
1271
1272     __END__;
1273
1274     cvReleaseMat( &denom );
1275     cvReleaseMat( &temp );
1276 }
1277
1278 /* End of file. */