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
51typedef void (*pointer_LMJac)( const CvMat* src, CvMat* dst );
52typedef void (*pointer_LMFunc)( const CvMat* src, CvMat* dst );
53
54void 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
60void 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 */
66void 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
166void 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
269void 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 */
446void 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
498