📄 sba_levmar.c
字号:
* to compute the corresponding columns of *all* A_ij through finite differences. A similar * strategy allows the computation of the B_ij. Overall, only cnp+pnp+1 objective function * evaluations are needed to compute the jacobian, much fewer compared to the m*cnp+n*pnp+1 * that would be required by the naive strategy of computing one column of the jacobian * per function evaluation. See Nocedal-Wright, ch. 7, pp. 169. Although this approach is * much faster compared to the naive strategy, it is not preferable to analytic jacobians, * since the latter are considerably faster to compute and result in fewer LM iterations. */static void sba_fdjac_x( double *p, /* I: current parameter estimate, (m*cnp+n*pnp)x1 */ struct sba_crsm *idxij, /* I: sparse matrix containing the location of x_ij in hx */ int *rcidxs, /* work array for the indexes of nonzero elements of a single sparse matrix row/column */ int *rcsubs, /* work array for the subscripts of nonzero elements in a single sparse matrix row/column */ double *jac, /* O: array for storing the approximated jacobian */ void *dat) /* I: points to a "fdj_data_x_" structure */{ register int i, j, ii, jj; double *pa, *pb, *pqr, *ppt; register double *pAB, *phx, *phxx; int n, m, nm, nnz, Asz, Bsz, ABsz, idx; double *tmpd; register double d; struct fdj_data_x_ *fdjd; void (*func)(double *p, struct sba_crsm *idxij, int *rcidxs, int *rcsubs, double *hx, void *adata); double *hx, *hxx; int cnp, pnp, mnp; void *adata; /* retrieve problem-specific information passed in *dat */ fdjd=(struct fdj_data_x_ *)dat; func=fdjd->func; cnp=fdjd->cnp; pnp=fdjd->pnp; mnp=fdjd->mnp; hx=fdjd->hx; hxx=fdjd->hxx; adata=fdjd->adata; n=idxij->nr; m=idxij->nc; pa=p; pb=p+m*cnp; Asz=mnp*cnp; Bsz=mnp*pnp; ABsz=Asz+Bsz; nm=(n>=m)? n : m; // max(n, m); tmpd=(double *)emalloc(nm*sizeof(double)); (*func)(p, idxij, fdjd->func_rcidxs, fdjd->func_rcsubs, hx, adata); // evaluate supplied function on current solution if(cnp){ // is motion varying? /* compute A_ij */ for(jj=0; jj<cnp; ++jj){ for(j=0; j<m; ++j){ pqr=pa+j*cnp; // j-th camera parameters /* determine d=max(SBA_DELTA_SCALE*|pqr[jj]|, SBA_MIN_DELTA), see HZ */ d=(double)(SBA_DELTA_SCALE)*pqr[jj]; // force evaluation d=FABS(d); if(d<SBA_MIN_DELTA) d=SBA_MIN_DELTA; tmpd[j]=d; pqr[jj]+=d; } (*func)(p, idxij, fdjd->func_rcidxs, fdjd->func_rcsubs, hxx, adata); for(j=0; j<m; ++j){ pqr=pa+j*cnp; // j-th camera parameters pqr[jj]-=tmpd[j]; /* restore */ d=1.0/tmpd[j]; /* invert so that divisions can be carried out faster as multiplications */ nnz=sba_crsm_col_elmidxs(idxij, j, rcidxs, rcsubs); /* find nonzero A_ij, i=0...n-1 */ for(i=0; i<nnz; ++i){ idx=idxij->val[rcidxs[i]]; phx=hx + idx*mnp; // set phx to point to hx_ij phxx=hxx + idx*mnp; // set phxx to point to hxx_ij pAB=jac + idx*ABsz; // set pAB to point to A_ij for(ii=0; ii<mnp; ++ii) pAB[ii*cnp+jj]=(phxx[ii]-phx[ii])*d; } } } } if(pnp){ // is structure varying? /* compute B_ij */ for(jj=0; jj<pnp; ++jj){ for(i=0; i<n; ++i){ ppt=pb+i*pnp; // i-th point parameters /* determine d=max(SBA_DELTA_SCALE*|ppt[jj]|, SBA_MIN_DELTA), see HZ */ d=(double)(SBA_DELTA_SCALE)*ppt[jj]; // force evaluation d=FABS(d); if(d<SBA_MIN_DELTA) d=SBA_MIN_DELTA; tmpd[i]=d; ppt[jj]+=d; } (*func)(p, idxij, fdjd->func_rcidxs, fdjd->func_rcsubs, hxx, adata); for(i=0; i<n; ++i){ ppt=pb+i*pnp; // i-th point parameters ppt[jj]-=tmpd[i]; /* restore */ d=1.0/tmpd[i]; /* invert so that divisions can be carried out faster as multiplications */ nnz=sba_crsm_row_elmidxs(idxij, i, rcidxs, rcsubs); /* find nonzero B_ij, j=0...m-1 */ for(j=0; j<nnz; ++j){ idx=idxij->val[rcidxs[j]]; phx=hx + idx*mnp; // set phx to point to hx_ij phxx=hxx + idx*mnp; // set phxx to point to hxx_ij pAB=jac + idx*ABsz + Asz; // set pAB to point to B_ij for(ii=0; ii<mnp; ++ii) pAB[ii*pnp+jj]=(phxx[ii]-phx[ii])*d; } } } } free(tmpd);}typedef int (*PLS)(double *A, double *B, double *x, int m, int iscolmaj);/* Bundle adjustment on camera and structure parameters * using the sparse Levenberg-Marquardt as described in HZ p. 568 * * Returns the number of iterations (>=0) if successfull, SBA_ERROR if failed */int sba_motstr_levmar_x( const int n, /* number of points */ const int m, /* number of images */ const int mcon,/* number of images (starting from the 1st) whose parameters should not be modified. * All A_ij (see below) with j<mcon are assumed to be zero */ char *vmask, /* visibility mask: vmask[i, j]=1 if point i visible in image j, 0 otherwise. nxm */ double *p, /* initial parameter vector p0: (a1, ..., am, b1, ..., bn). * aj are the image j parameters, bi are the i-th point parameters, * size m*cnp + n*pnp */ const int cnp,/* number of parameters for ONE camera; e.g. 6 for Euclidean cameras */ const int pnp,/* number of parameters for ONE point; e.g. 3 for Euclidean points */ double *x, /* measurements vector: (x_11^T, .. x_1m^T, ..., x_n1^T, .. x_nm^T)^T where * x_ij is the projection of the i-th point on the j-th image. * NOTE: some of the x_ij might be missing, if point i is not visible in image j; * see vmask[i, j], max. size n*m*mnp */ double *covx, /* measurements covariance matrices: (Sigma_x_11, .. Sigma_x_1m, ..., Sigma_x_n1, .. Sigma_x_nm), * where Sigma_x_ij is the mnp x mnp covariance of x_ij stored row-by-row. Set to NULL if no * covariance estimates are available (identity matrices are implicitly used in this case). * NOTE: a certain Sigma_x_ij is missing if the corresponding x_ij is also missing; * see vmask[i, j], max. size n*m*mnp*mnp */ const int mnp,/* number of parameters for EACH measurement; usually 2 */ void (*func)(double *p, struct sba_crsm *idxij, int *rcidxs, int *rcsubs, double *hx, void *adata), /* functional relation describing measurements. Given a parameter vector p, * computes a prediction of the measurements \hat{x}. p is (m*cnp + n*pnp)x1, * \hat{x} is (n*m*mnp)x1, maximum * rcidxs, rcsubs are max(m, n) x 1, allocated by the caller and can be used * as working memory */ void (*fjac)(double *p, struct sba_crsm *idxij, int *rcidxs, int *rcsubs, double *jac, void *adata), /* function to evaluate the sparse jacobian dX/dp. * The Jacobian is returned in jac as * (dx_11/da_1, ..., dx_1m/da_m, ..., dx_n1/da_1, ..., dx_nm/da_m, * dx_11/db_1, ..., dx_1m/db_1, ..., dx_n1/db_n, ..., dx_nm/db_n), or (using HZ's notation), * jac=(A_11, B_11, ..., A_1m, B_1m, ..., A_n1, B_n1, ..., A_nm, B_nm) * Notice that depending on idxij, some of the A_ij and B_ij might be missing. * Note also that A_ij and B_ij are mnp x cnp and mnp x pnp matrices resp. and they * should be stored in jac in row-major order. * rcidxs, rcsubs are max(m, n) x 1, allocated by the caller and can be used * as working memory * * If NULL, the jacobian is approximated by repetitive func calls and finite * differences. This is computationally inefficient and thus NOT recommended. */ void *adata, /* pointer to possibly additional data, passed uninterpreted to func, fjac */ const int itmax, /* I: maximum number of iterations. itmax==0 signals jacobian verification followed by immediate return */ const int verbose, /* I: verbosity */ const double opts[SBA_OPTSSZ], /* I: minim. options [\mu, \epsilon1, \epsilon2, \epsilon3, \epsilon4]. Respectively the scale factor for initial \mu, * stopping thresholds for ||J^T e||_inf, ||dp||_2, ||e||_2 and (||e||_2-||e_new||_2)/||e||_2 */ double info[SBA_INFOSZ] /* O: information regarding the minimization. Set to NULL if don't care * info[0]=||e||_2 at initial p. * info[1-4]=[ ||e||_2, ||J^T e||_inf, ||dp||_2, mu/max[J^T J]_ii ], all computed at estimated p. * info[5]= # iterations, * info[6]=reason for terminating: 1 - stopped by small gradient J^T e * 2 - stopped by small dp * 3 - stopped by itmax * 4 - stopped by small relative reduction in ||e||_2 * 5 - stopped by small ||e||_2 * 6 - too many attempts to increase damping. Restart with increased mu * 7 - stopped by invalid (i.e. NaN or Inf) "func" values. This is a user error * info[7]= # function evaluations * info[8]= # jacobian evaluations * info[9]= # number of linear systems solved, i.e. number of attempts for reducing error */){register int i, j, ii, jj, k, l;int nvis, nnz, retval;/* The following are work arrays that are dynamically allocated by sba_motstr_levmar_x() */double *jac; /* work array for storing the jacobian, max. size n*m*(mnp*cnp + mnp*pnp) */double *U; /* work array for storing the U_j in the order U_1, ..., U_m, size m*cnp*cnp */double *V; /* work array for storing the *strictly upper triangles* of V_i in the order V_1, ..., V_n, size n*pnp*pnp. * V also stores the lower triangles of (V*_i)^-1 in the order (V*_1)^-1, ..., (V*_n)^-1. * Note that diagonal elements of V_1 are saved in diagUV */double *e; /* work array for storing the e_ij in the order e_11, ..., e_1m, ..., e_n1, ..., e_nm, max. size n*m*mnp */double *eab; /* work array for storing the ea_j & eb_i in the order ea_1, .. ea_m eb_1, .. eb_n size m*cnp + n*pnp */double *E; /* work array for storing the e_j in the order e_1, .. e_m, size m*cnp *//* Notice that the blocks W_ij, Y_ij are zero iff A_ij (equivalently B_ij) is zero. This means * that the matrix consisting of blocks W_ij is itself sparse, similarly to the * block matrix made up of the A_ij and B_ij (i.e. jac) */double *W; /* work array for storing the W_ij in the order W_11, ..., W_1m, ..., W_n1, ..., W_nm, max. size n*m*cnp*pnp */double *Yj; /* work array for storing the Y_ij for a *fixed* j in the order Y_1j, Y_nj, max. size n*cnp*pnp */double *YWt; /* work array for storing \sum_i Y_ij W_ik^T, size cnp*cnp */double *S; /* work array for storing the block array S_jk, size m*m*cnp*cnp */double *dp; /* work array for storing the parameter vector updates da_1, ..., da_m, db_1, ..., db_n, size m*cnp + n*pnp */double *Wtda; /* work array for storing \sum_j W_ij^T da_j, size pnp */double *wght= /* work array for storing the weights computed from the covariance inverses, max. size n*m*mnp*mnp */ NULL;/* Of the above arrays, jac, e, W, Yj, wght are sparse and * U, V, eab, E, S, dp are dense. Sparse arrays (except Yj) are indexed * through idxij (see below), that is with the same mechanism as the input * measurements vector x */double *pa, *pb, *ea, *eb, *dpa, *dpb; /* pointers into p, jac, eab and dp respectively *//* submatrices sizes */int Asz, Bsz, ABsz, Usz, Vsz, Wsz, Ysz, esz, easz, ebsz, YWtsz, Wtdasz, Sblsz, covsz;int Sdim; /* S matrix actual dimension */register double *ptr1, *ptr2, *ptr3, *ptr4, sum;struct sba_crsm idxij; /* sparse matrix containing the location of x_ij in x. This is also * the location of A_ij, B_ij in jac, etc. * This matrix can be thought as a map from a sparse set of pairs (i, j) to a continuous * index k and it is used to efficiently lookup the memory locations where the non-zero * blocks of a sparse matrix/vector are stored */int maxCvis, /* max. of projections of a single point across cameras, <=m */ maxPvis, /* max. of projections in a single camera across points, <=n */ maxCPvis, /* max. of the above */ *rcidxs, /* work array for the indexes corresponding to the nonzero elements of a single row or column in a sparse matrix, size max(n, m) */ *rcsubs; /* work array for the subscripts of nonzero elements in a single row or column of a sparse matrix, size max(n, m) *//* The following variables are needed by the LM algorithm */register int itno; /* iteration counter */int issolved;/* temporary work arrays that are dynamically allocated */double *hx, /* \hat{x}_i, max. size m*n*mnp */ *diagUV, /* diagonals of U_j, V_i, size m*cnp + n*pnp */ *pdp; /* p + dp, size m*cnp + n*pnp */double *diagU, *diagV; /* pointers into diagUV */register double mu, /* damping constant */ tmp; /* mainly used in matrix & vector multiplications */double p_eL2, eab_inf, pdp_eL2; /* ||e(p)||_2, ||J^T e||_inf, ||e(p+dp)||_2 */double p_L2, dp_L2=DBL_MAX, dF, dL;double tau=FABS(opts[0]), eps1=FABS(opts[1]), eps2=FABS(opts[2]), eps2_sq=opts[2]*opts[2], eps3_sq=opts[3]*opts[3], eps4_sq=opts[4]*opts[4];double init_p_eL2;int nu=2, nu2, stop=0, nfev, njev=0, nlss=0;int nobs, nvars;const int mmcon=m-mcon;PLS linsolver=NULL;int (*matinv)(double *A, int m)=NULL;struct fdj_data_x_ fdj_data;void *jac_adata;/* Initialization */ mu=eab_inf=0.0; /* -Wall */ /* block sizes */ Asz=mnp * cnp; Bsz=mnp * pnp; ABsz=Asz + Bsz; Usz=cnp * cnp; Vsz=pnp * pnp; Wsz=cnp * pnp; Ysz=cnp * pnp; esz=mnp; easz=cnp; ebsz=pnp; YWtsz=cnp * cnp; Wtdasz=pnp; Sblsz=cnp * cnp; Sdim=mmcon * cnp; covsz=mnp * mnp; /* count total number of visible image points */ for(i=nvis=0, jj=n*m; i<jj; ++i) nvis+=(vmask[i]!=0); nobs=nvis*mnp; nvars=m*cnp + n*pnp; if(nobs<nvars){ fprintf(stderr, "SBA: sba_motstr_levmar_x() cannot solve a problem with fewer measurements [%d] than unknowns [%d]\n", nobs, nvars); return SBA_ERROR; } /* allocate & fill up the idxij structure */ sba_crsm_alloc(&idxij, n, m, nvis); for(i=k=0; i<n; ++i){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -