Update the trunk to the OpenCV's CVS (2008-07-14)
[opencv] / cvaux / src / cvlevmartrif.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 "_cvaux.h"
43
44 #include "cvtypes.h"
45 #include <float.h>
46 #include <limits.h>
47 #include "cv.h"
48
49 /* Valery Mosyagin */
50
51 typedef void (*pointer_LMJac)( const CvMat* src, CvMat* dst );
52 typedef void (*pointer_LMFunc)( const CvMat* src, CvMat* dst );
53
54 void cvLevenbergMarquardtOptimization(pointer_LMJac JacobianFunction,
55                                     pointer_LMFunc function,
56                                     /*pointer_Err error_function,*/
57                                     CvMat *X0,CvMat *observRes,CvMat *resultX,
58                                     int maxIter,double epsilon);
59
60 void icvReconstructPointsFor3View( CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
61                                 CvMat* projPoints1,CvMat* projPoints2,CvMat* projPoints3,
62                                 CvMat* points4D);
63
64
65 /* Jacobian computation for trifocal case */
66 void icvJacobianFunction_ProjTrifocal(const CvMat *vectX,CvMat *Jacobian)
67 {
68     CV_FUNCNAME( "icvJacobianFunction_ProjTrifocal" );
69     __BEGIN__;
70
71     /* Test data for errors */
72     if( vectX == 0 || Jacobian == 0 )
73     {
74         CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
75     }
76
77     if( !CV_IS_MAT(vectX) || !CV_IS_MAT(Jacobian) )
78     {
79         CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
80     }
81
82     int numPoints;
83     numPoints = (vectX->rows - 36)/4;
84
85     if( numPoints < 1 )//!!! Need to correct this minimal number of points
86     {
87         CV_ERROR( CV_StsUnmatchedSizes, "number of points must be more than 0" );
88     }
89
90     if( Jacobian->rows == numPoints*6 || Jacobian->cols != 36+numPoints*4 )
91     {
92         CV_ERROR( CV_StsUnmatchedSizes, "Size of Jacobian is not correct it must be 6*numPoints x (36+numPoints*4)" );
93     }
94
95     /* Computed Jacobian in a given point */
96     /* This is for function with 3 projection matrices */
97     /* vector X consists of projection matrices and points3D */
98     /* each 3D points has X,Y,Z,W */
99     /* each projection matrices has 3x4 coeffs */
100     /* For N points 4D we have Jacobian 2N x (12*3+4N) */
101
102     /* Will store derivates as  */
103     /* Fill Jacobian matrix */
104     int currProjPoint;
105     int currMatr;
106     
107     cvZero(Jacobian);
108     for( currMatr = 0; currMatr < 3; currMatr++ )
109     {
110         double p[12];
111         for( int i=0;i<12;i++ )
112         {
113             p[i] = cvmGet(vectX,currMatr*12+i,0);
114         }
115
116         int currVal = 36;
117         for( currProjPoint = 0; currProjPoint < numPoints; currProjPoint++ )
118         {
119             /* Compute */
120             double X[4];
121             X[0] = cvmGet(vectX,currVal++,0);
122             X[1] = cvmGet(vectX,currVal++,0);
123             X[2] = cvmGet(vectX,currVal++,0);
124             X[3] = cvmGet(vectX,currVal++,0);
125
126             double piX[3];
127             piX[0] = X[0]*p[0] + X[1]*p[1] + X[2]*p[2]  + X[3]*p[3];
128             piX[1] = X[0]*p[4] + X[1]*p[5] + X[2]*p[6]  + X[3]*p[7];
129             piX[2] = X[0]*p[8] + X[1]*p[9] + X[2]*p[10] + X[3]*p[11];
130
131             int i,j;
132             /* fill derivate by point */
133
134             double tmp3 = 1/(piX[2]*piX[2]);
135
136             double tmp1 = -piX[0]*tmp3;
137             double tmp2 = -piX[1]*tmp3;
138             for( j = 0; j < 2; j++ )//for x and y
139             {
140                 for( i = 0; i < 4; i++ )// for X,Y,Z,W
141                 {
142                     cvmSet( Jacobian, 
143                             currMatr*numPoints*2+currProjPoint*2+j, 36+currProjPoint*4+i,
144                             (p[j*4+i]*piX[2]-p[8+i]*piX[j]) * tmp3  );
145                 }
146             }
147                 /* fill derivate by projection matrix */
148             for( i = 0; i < 4; i++ )
149             {
150                 /* derivate for x */
151                 cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2,currMatr*12+i,X[i]/piX[2]);//x' p1i
152                 cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2,currMatr*12+8+i,X[i]*tmp1);//x' p3i
153
154                 /* derivate for y */
155                 cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2+1,currMatr*12+4+i,X[i]/piX[2]);//y' p2i
156                 cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2+1,currMatr*12+8+i,X[i]*tmp2);//y' p3i
157             }
158
159         }
160     }
161
162     __END__;
163     return;
164 }
165
166 void icvFunc_ProjTrifocal(const CvMat *vectX, CvMat *resFunc)
167 {
168     /* Computes function in a given point */
169     /* Computers project points using 3 projection matrices and points 3D */
170
171     /* vector X consists of projection matrices and points3D */
172     /* each projection matrices has 3x4 coeffs */
173     /* each 3D points has X,Y,Z,W(?) */
174
175     /* result of function is projection of N 3D points using 3 projection matrices */
176     /* projected points store as (projection by matrix P1),(projection by matrix P2),(projection by matrix P3) */
177     /* each projection is x1,y1,x2,y2,x3,y3,x4,y4 */
178
179     /* Compute projection of points */
180
181     /* Fill projection matrices */
182
183     CV_FUNCNAME( "icvFunc_ProjTrifocal" );
184     __BEGIN__;
185
186     /* Test data for errors */
187     if( vectX == 0 || resFunc == 0 )
188     {
189         CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
190     }
191
192     if( !CV_IS_MAT(vectX) || !CV_IS_MAT(resFunc) )
193     {
194         CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
195     }
196
197     int numPoints;
198     numPoints = (vectX->rows - 36)/4;
199
200     if( numPoints < 1 )//!!! Need to correct this minimal number of points
201     {
202         CV_ERROR( CV_StsUnmatchedSizes, "number of points must be more than 0" );
203     }
204
205     if( resFunc->rows == 2*numPoints*3 || resFunc->cols != 1 )
206     {
207         CV_ERROR( CV_StsUnmatchedSizes, "Size of resFunc is not correct it must be 2*numPoints*3 x 1");
208     }
209
210
211     CvMat projMatrs[3];
212     double projMatrs_dat[36];
213     projMatrs[0] = cvMat(3,4,CV_64F,projMatrs_dat);
214     projMatrs[1] = cvMat(3,4,CV_64F,projMatrs_dat+12);
215     projMatrs[2] = cvMat(3,4,CV_64F,projMatrs_dat+24);
216
217     CvMat point3D;
218     double point3D_dat[3];
219     point3D = cvMat(3,1,CV_64F,point3D_dat);
220
221     int currMatr;
222     int currV;
223     int i,j;
224
225     currV=0;
226     for( currMatr = 0; currMatr < 3; currMatr++ )
227     {
228         for( i = 0; i < 3; i++ )
229         {
230             for( j = 0;j < 4; j++ )
231             {
232                 double val = cvmGet(vectX,currV,0);
233                 cvmSet(&projMatrs[currMatr],i,j,val);
234                 currV++;
235             }
236         }
237     }
238
239     /* Project points */
240     int currPoint;
241     CvMat point4D;
242     double point4D_dat[4];
243     point4D = cvMat(4,1,CV_64F,point4D_dat);
244     for( currPoint = 0; currPoint < numPoints; currPoint++ )
245     {
246         /* get curr point */
247         point4D_dat[0] = cvmGet(vectX,currV++,0);
248         point4D_dat[1] = cvmGet(vectX,currV++,0);
249         point4D_dat[2] = cvmGet(vectX,currV++,0);
250         point4D_dat[3] = cvmGet(vectX,currV++,0);
251
252         for( currMatr = 0; currMatr < 3; currMatr++ )
253         {
254             /* Compute projection for current point */
255             cvmMul(&projMatrs[currMatr],&point4D,&point3D);
256             double z = point3D_dat[2];
257             cvmSet(resFunc,currMatr*numPoints*2 + currPoint*2,  0,point3D_dat[0]/z);
258             cvmSet(resFunc,currMatr*numPoints*2 + currPoint*2+1,0,point3D_dat[1]/z);
259         }
260     }
261
262     __END__;
263     return;
264 }
265
266
267 /*----------------------------------------------------------------------------------------*/
268
269 void icvOptimizeProjectionTrifocal(CvMat **projMatrs,CvMat **projPoints,
270                                 CvMat **resultProjMatrs, CvMat *resultPoints4D)
271 {
272
273     CvMat *optimX    = 0;
274     CvMat *points4D  = 0;
275     CvMat *vectorX0  = 0;
276     CvMat *observRes = 0;
277     //CvMat *error     = 0;
278
279     CV_FUNCNAME( "icvOptimizeProjectionTrifocal" );
280     __BEGIN__;
281
282     /* Test data for errors */
283     if( projMatrs == 0 || projPoints == 0 || resultProjMatrs == 0 || resultPoints4D == 0)
284     {
285         CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
286     }
287
288     if( !CV_IS_MAT(resultPoints4D) )
289     {
290         CV_ERROR( CV_StsUnsupportedFormat, "resultPoints4D must be a matrix" );
291     }
292
293     int numPoints;
294     numPoints = resultPoints4D->cols;
295     if( numPoints < 1 )
296     {
297         CV_ERROR( CV_StsOutOfRange, "Number points of resultPoints4D must be more than 0" );
298     }
299
300     if( resultPoints4D->rows != 4 )
301     {
302         CV_ERROR( CV_StsUnmatchedSizes, "Number of coordinates of points4D must be 4" );
303     }
304
305     int i;
306     for( i = 0; i < 3; i++ )
307     {
308         if( projMatrs[i] == 0 )
309         {
310             CV_ERROR( CV_StsNullPtr, "Some of projMatrs is a NULL pointer" );
311         }
312
313         if( projPoints[i] == 0 )
314         {
315             CV_ERROR( CV_StsNullPtr, "Some of projPoints is a NULL pointer" );
316         }
317     
318         if( resultProjMatrs[i] == 0 )
319         {
320             CV_ERROR( CV_StsNullPtr, "Some of resultProjMatrs is a NULL pointer" );
321         }
322
323         /* ----------- test for matrix ------------- */
324         if( !CV_IS_MAT(projMatrs[i]) )
325         {
326             CV_ERROR( CV_StsUnsupportedFormat, "Each of projMatrs must be a matrix" );
327         }
328
329         if( !CV_IS_MAT(projPoints[i]) )
330         {
331             CV_ERROR( CV_StsUnsupportedFormat, "Each of projPoints must be a matrix" );
332         }
333
334         if( !CV_IS_MAT(resultProjMatrs[i]) )
335         {
336             CV_ERROR( CV_StsUnsupportedFormat, "Each of resultProjMatrs must be a matrix" );
337         }
338
339         /* ------------- Test sizes --------------- */
340         if( projMatrs[i]->rows != 3 || projMatrs[i]->cols != 4 )
341         {
342             CV_ERROR( CV_StsUnmatchedSizes, "Size of projMatr must be 3x4" );
343         }
344
345         if( projPoints[i]->rows != 2 || projPoints[i]->cols != numPoints )
346         {
347             CV_ERROR( CV_StsUnmatchedSizes, "Size of resultProjMatrs must be 3x4" );
348         }
349
350         if( resultProjMatrs[i]->rows != 3 || resultProjMatrs[i]->cols != 4 )
351         {
352             CV_ERROR( CV_StsUnmatchedSizes, "Size of resultProjMatrs must be 3x4" );
353         }
354     }
355
356
357     /* Allocate memory for points 4D */
358     CV_CALL( points4D  = cvCreateMat(4,numPoints,CV_64F) );
359     CV_CALL( vectorX0  = cvCreateMat(36 + numPoints*4,1,CV_64F) );
360     CV_CALL( observRes = cvCreateMat(2*numPoints*3,1,CV_64F) );
361     CV_CALL( optimX    = cvCreateMat(36+numPoints*4,1,CV_64F) );
362     //CV_CALL( error     = cvCreateMat(numPoints*2*3,1,CV_64F) );
363
364
365     /* Reconstruct points 4D using projected points and projection matrices */
366     icvReconstructPointsFor3View( projMatrs[0],projMatrs[1],projMatrs[2],
367                                   projPoints[0],projPoints[1],projPoints[2],
368                                   points4D);
369
370
371
372     /* Fill observed points on images */
373     /* result of function is projection of N 3D points using 3 projection matrices */
374     /* projected points store as (projection by matrix P1),(projection by matrix P2),(projection by matrix P3) */
375     /* each projection is x1,y1,x2,y2,x3,y3,x4,y4 */
376     int currMatr;
377     for( currMatr = 0; currMatr < 3; currMatr++ )
378     {
379         for( i = 0; i < numPoints; i++ )
380         {
381             cvmSet(observRes,currMatr*numPoints*2+i*2  ,0,cvmGet(projPoints[currMatr],0,i) );/* x */
382             cvmSet(observRes,currMatr*numPoints*2+i*2+1,0,cvmGet(projPoints[currMatr],1,i) );/* y */
383         }
384     }
385
386     /* Fill with projection matrices */
387     for( currMatr = 0; currMatr < 3; currMatr++ )
388     {
389         int i;
390         for( i = 0; i < 12; i++ )
391         {
392             cvmSet(vectorX0,currMatr*12+i,0,cvmGet(projMatrs[currMatr],i/4,i%4));
393         }
394     }
395
396     /* Fill with 4D points */
397
398     int currPoint;
399     for( currPoint = 0; currPoint < numPoints; currPoint++ )
400     {
401         cvmSet(vectorX0,36 + currPoint*4 + 0,0,cvmGet(points4D,0,currPoint));
402         cvmSet(vectorX0,36 + currPoint*4 + 1,0,cvmGet(points4D,1,currPoint));
403         cvmSet(vectorX0,36 + currPoint*4 + 2,0,cvmGet(points4D,2,currPoint));
404         cvmSet(vectorX0,36 + currPoint*4 + 3,0,cvmGet(points4D,3,currPoint));
405     }
406
407     
408     /* Allocate memory for result */
409     cvLevenbergMarquardtOptimization( icvJacobianFunction_ProjTrifocal, icvFunc_ProjTrifocal,
410                                       vectorX0,observRes,optimX,100,1e-6);
411
412     /* Copy results */
413     for( currMatr = 0; currMatr < 3; currMatr++ )
414     {
415         /* Copy projection matrices */
416         for(int i=0;i<12;i++)
417         {
418             cvmSet(resultProjMatrs[currMatr],i/4,i%4,cvmGet(optimX,currMatr*12+i,0));
419         }
420     }
421
422     /* Copy 4D points */
423     for( currPoint = 0; currPoint < numPoints; currPoint++ )
424     {
425         cvmSet(resultPoints4D,0,currPoint,cvmGet(optimX,36 + currPoint*4,0));
426         cvmSet(resultPoints4D,1,currPoint,cvmGet(optimX,36 + currPoint*4+1,0));
427         cvmSet(resultPoints4D,2,currPoint,cvmGet(optimX,36 + currPoint*4+2,0));
428         cvmSet(resultPoints4D,3,currPoint,cvmGet(optimX,36 + currPoint*4+3,0));
429     }
430
431     __END__;
432
433     /* Free allocated memory */
434     cvReleaseMat(&optimX);
435     cvReleaseMat(&points4D);
436     cvReleaseMat(&vectorX0);
437     cvReleaseMat(&observRes);
438
439     return;
440
441
442 }
443
444 /*------------------------------------------------------------------------------*/
445 /* Create good points using status information */
446 void icvCreateGoodPoints(CvMat *points,CvMat **goodPoints, CvMat *status)
447 {
448     *goodPoints = 0;
449
450     CV_FUNCNAME( "icvCreateGoodPoints" );
451     __BEGIN__;
452
453     int numPoints;
454     numPoints = points->cols;
455
456     if( numPoints < 1 )
457     {
458         CV_ERROR( CV_StsOutOfRange, "Number of points must be more than 0" );
459     }
460
461     int numCoord;
462     numCoord = points->rows;
463     if( numCoord < 1 )
464     {
465         CV_ERROR( CV_StsOutOfRange, "Number of points coordinates must be more than 0" );
466     }
467
468     /* Define number of good points */
469     int goodNum;
470     int i,j;
471
472     goodNum = 0;
473     for( i = 0; i < numPoints; i++)
474     {
475         if( cvmGet(status,0,i) > 0 )
476             goodNum++;
477     }
478
479     /* Allocate memory for good points */
480     CV_CALL( *goodPoints = cvCreateMat(numCoord,goodNum,CV_64F) );
481
482     for( i = 0; i < numCoord; i++ )
483     {
484         int currPoint = 0;
485         for( j = 0; j < numPoints; j++)
486         {
487             if( cvmGet(status,0,j) > 0 )
488             {
489                 cvmSet(*goodPoints,i,currPoint,cvmGet(points,i,j));
490                 currPoint++;
491             }
492         }
493     }
494     __END__;
495     return;
496 }
497