Move the sources to trunk
[opencv] / cvaux / src / cvlevmar.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 #include "cvtypes.h"
44 #include <float.h>
45 #include <limits.h>
46 #include "cv.h"
47
48 /* Valery Mosyagin */
49
50 //#define TRACKLEVMAR
51
52 typedef void (*pointer_LMJac)( const CvMat* src, CvMat* dst );
53 typedef void (*pointer_LMFunc)( const CvMat* src, CvMat* dst );
54
55 /* Optimization using Levenberg-Marquardt */
56 void cvLevenbergMarquardtOptimization(pointer_LMJac JacobianFunction,
57                                     pointer_LMFunc function,
58                                     /*pointer_Err error_function,*/
59                                     CvMat *X0,CvMat *observRes,CvMat *resultX,
60                                     int maxIter,double epsilon)
61 {
62     /* This is not sparce method */
63     /* Make optimization using  */
64     /* func - function to compute */
65     /* uses function to compute jacobian */
66
67     /* Allocate memory */
68     CvMat *vectX = 0;
69     CvMat *vectNewX = 0;
70     CvMat *resFunc = 0;
71     CvMat *resNewFunc = 0;
72     CvMat *error = 0;
73     CvMat *errorNew = 0;
74     CvMat *Jac = 0;
75     CvMat *delta = 0;
76     CvMat *matrJtJ = 0;
77     CvMat *matrJtJN = 0;
78     CvMat *matrJt = 0;
79     CvMat *vectB = 0;
80    
81     CV_FUNCNAME( "cvLevenbegrMarquardtOptimization" );
82     __BEGIN__;
83
84
85     if( JacobianFunction == 0 || function == 0 || X0 == 0 || observRes == 0 || resultX == 0 )
86     {
87         CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
88     }
89
90     if( !CV_IS_MAT(X0) || !CV_IS_MAT(observRes) || !CV_IS_MAT(resultX) )
91     {
92         CV_ERROR( CV_StsUnsupportedFormat, "Some of input parameters must be a matrices" );
93     }
94
95
96     int numVal;
97     int numFunc;
98     double valError;
99     double valNewError;
100
101     numVal = X0->rows;
102     numFunc = observRes->rows;
103
104     /* test input data */
105     if( X0->cols != 1 )
106     {
107         CV_ERROR( CV_StsUnmatchedSizes, "Number of colomn of vector X0 must be 1" );
108     }
109     
110     if( observRes->cols != 1 )
111     {
112         CV_ERROR( CV_StsUnmatchedSizes, "Number of colomn of vector observed rusult must be 1" );
113     }
114
115     if( resultX->cols != 1 || resultX->rows != numVal )
116     {
117         CV_ERROR( CV_StsUnmatchedSizes, "Size of result vector X must be equals to X0" );
118     }
119
120     if( maxIter <= 0  )
121     {
122         CV_ERROR( CV_StsUnmatchedSizes, "Number of maximum iteration must be > 0" );
123     }
124
125     if( epsilon < 0 )
126     {
127         CV_ERROR( CV_StsUnmatchedSizes, "Epsilon must be >= 0" );
128     }
129
130     /* copy x0 to current value of x */
131     CV_CALL( vectX      = cvCreateMat(numVal, 1,      CV_64F) );
132     CV_CALL( vectNewX   = cvCreateMat(numVal, 1,      CV_64F) );
133     CV_CALL( resFunc    = cvCreateMat(numFunc,1,      CV_64F) );
134     CV_CALL( resNewFunc = cvCreateMat(numFunc,1,      CV_64F) );
135     CV_CALL( error      = cvCreateMat(numFunc,1,      CV_64F) );
136     CV_CALL( errorNew   = cvCreateMat(numFunc,1,      CV_64F) );
137     CV_CALL( Jac        = cvCreateMat(numFunc,numVal, CV_64F) );
138     CV_CALL( delta      = cvCreateMat(numVal, 1,      CV_64F) );
139     CV_CALL( matrJtJ    = cvCreateMat(numVal, numVal, CV_64F) );
140     CV_CALL( matrJtJN   = cvCreateMat(numVal, numVal, CV_64F) );
141     CV_CALL( matrJt     = cvCreateMat(numVal, numFunc,CV_64F) );
142     CV_CALL( vectB      = cvCreateMat(numVal, 1,      CV_64F) );
143
144     cvCopy(X0,vectX);
145
146     /* ========== Main optimization loop ============ */
147     double change;
148     int currIter;
149     double alpha;
150
151     change = 1;
152     currIter = 0;
153     alpha = 0.001;
154
155     do {
156
157         /* Compute value of function */
158         function(vectX,resFunc);
159         /* Print result of function to file */
160
161         /* Compute error */
162         cvSub(observRes,resFunc,error);        
163         
164         //valError = error_function(observRes,resFunc);
165         /* Need to use new version of computing error (norm) */
166         valError = cvNorm(observRes,resFunc);
167
168         /* Compute Jacobian for given point vectX */
169         JacobianFunction(vectX,Jac);
170
171         /* Define optimal delta for J'*J*delta=J'*error */
172         /* compute J'J */
173         cvMulTransposed(Jac,matrJtJ,1);
174         
175         cvCopy(matrJtJ,matrJtJN);
176
177         /* compute J'*error */
178         cvTranspose(Jac,matrJt);
179         cvmMul(matrJt,error,vectB);
180
181
182         /* Solve normal equation for given alpha and Jacobian */
183         do
184         {
185             /* Increase diagonal elements by alpha */
186             for( int i = 0; i < numVal; i++ )
187             {
188                 double val;
189                 val = cvmGet(matrJtJ,i,i);
190                 cvmSet(matrJtJN,i,i,(1+alpha)*val);
191             }
192
193             /* Solve system to define delta */
194             cvSolve(matrJtJN,vectB,delta,CV_SVD);
195
196             /* We know delta and we can define new value of vector X */
197             cvAdd(vectX,delta,vectNewX);
198
199             /* Compute result of function for new vector X */
200             function(vectNewX,resNewFunc);
201             cvSub(observRes,resNewFunc,errorNew);
202
203             valNewError = cvNorm(observRes,resNewFunc);
204
205             currIter++;
206
207             if( valNewError < valError )
208             {/* accept new value */
209                 valError = valNewError;
210
211                 /* Compute relative change of required parameter vectorX. change = norm(curr-prev) / norm(curr) )  */
212                 change = cvNorm(vectX, vectNewX, CV_RELATIVE_L2);
213
214                 alpha /= 10;
215                 cvCopy(vectNewX,vectX);
216                 break;
217             }
218             else
219             {
220                 alpha *= 10;
221             }
222
223         } while ( currIter < maxIter  );
224         /* new value of X and alpha were accepted */
225
226     } while ( change > epsilon && currIter < maxIter );
227
228
229     /* result was computed */
230     cvCopy(vectX,resultX);
231
232     __END__;
233
234     cvReleaseMat(&vectX);
235     cvReleaseMat(&vectNewX);
236     cvReleaseMat(&resFunc);
237     cvReleaseMat(&resNewFunc);
238     cvReleaseMat(&error);
239     cvReleaseMat(&errorNew);
240     cvReleaseMat(&Jac);
241     cvReleaseMat(&delta);
242     cvReleaseMat(&matrJtJ);
243     cvReleaseMat(&matrJtJN);
244     cvReleaseMat(&matrJt);
245     cvReleaseMat(&vectB);
246
247     return;
248 }
249
250 /*------------------------------------------------------------------------------*/
251 #if 0
252 //tests
253 void Jac_Func2(CvMat *vectX,CvMat *Jac)
254 {
255     double x = cvmGet(vectX,0,0);
256     double y = cvmGet(vectX,1,0);
257     cvmSet(Jac,0,0,2*(x-2));
258     cvmSet(Jac,0,1,2*(y+3));
259
260     cvmSet(Jac,1,0,1);
261     cvmSet(Jac,1,1,1);
262     return;
263 }
264
265 void Res_Func2(CvMat *vectX,CvMat *res)
266 {
267     double x = cvmGet(vectX,0,0);
268     double y = cvmGet(vectX,1,0);
269     cvmSet(res,0,0,(x-2)*(x-2)+(y+3)*(y+3));
270     cvmSet(res,1,0,x+y);
271
272     return;
273 }
274
275
276 double Err_Func2(CvMat *obs,CvMat *res)
277 {
278     CvMat *tmp;
279     tmp = cvCreateMat(obs->rows,1,CV_64F);
280     cvSub(obs,res,tmp);
281
282     double e;
283     e = cvNorm(tmp);
284
285     return e;
286 }
287
288
289 void TestOptimX2Y2()
290 {
291     CvMat vectX0;
292     double vectX0_dat[2];
293     vectX0 = cvMat(2,1,CV_64F,vectX0_dat);
294     vectX0_dat[0] = 5;
295     vectX0_dat[1] = -7;
296
297     CvMat observRes;
298     double observRes_dat[2];
299     observRes = cvMat(2,1,CV_64F,observRes_dat);
300     observRes_dat[0] = 0;
301     observRes_dat[1] = -1;
302     observRes_dat[0] = 0;
303     observRes_dat[1] = -1.2;
304
305     CvMat optimX;
306     double optimX_dat[2];
307     optimX = cvMat(2,1,CV_64F,optimX_dat);
308
309
310     LevenbegrMarquardtOptimization( Jac_Func2, Res_Func2, Err_Func2,
311                                     &vectX0,&observRes,&optimX,100,0.000001);
312
313     return;
314
315 }
316
317 #endif
318
319
320