📄 sba_levmar.c
字号:
}/*if(!(itno%100)){ printf("Current estimate: "); for(i=0; i<nvars; ++i) printf("%.9g ", p[i]); printf("-- errors %.9g %0.9g\n", eab_inf, p_eL2);}*/ /* check for convergence */ if((eab_inf <= eps1)){ dp_L2=0.0; /* no increment for p in this case */ stop=1; break; } /* compute initial damping factor */ if(itno==0){ for(i=mcon*cnp, tmp=DBL_MIN; i<nvars; ++i) if(diagUV[i]>tmp) tmp=diagUV[i]; /* find max diagonal element */ mu=tau*tmp; } /* determine increment using adaptive damping */ while(1){ /* augment U, V */ for(j=mcon; j<m; ++j){ ptr1=U + j*Usz; // set ptr1 to point to U_j for(i=0; i<cnp; ++i) ptr1[i*cnp+i]+=mu; } for(i=0; i<n; ++i){ ptr1=V + i*Vsz; // set ptr1 to point to V_i for(j=0; j<pnp; ++j) ptr1[j*pnp+j]+=mu; /* compute V*_i^-1. * Recall that only the upper triangle of the symmetric pnp x pnp matrix V*_i * is stored in ptr1; its (also symmetric) inverse is saved in the lower triangle of ptr1 */ /* inverting V*_i with LDLT seems to result in faster overall execution compared to when using LU or Cholesky */ //j=sba_symat_invert_LU(ptr1, pnp); matinv=sba_symat_invert_LU; //j=sba_symat_invert_Chol(ptr1, pnp); matinv=sba_symat_invert_Chol; j=sba_symat_invert_BK(ptr1, pnp); matinv=sba_symat_invert_BK; if(!j){ fprintf(stderr, "SBA: singular matrix V*_i (i=%d) in sba_motstr_levmar_x(), increasing damping\n", i); goto moredamping; // increasing damping will eventually make V*_i diagonally dominant, thus nonsingular //retval=SBA_ERROR; //goto freemem_and_return; } } _dblzero(E, m*easz); /* clear all e_j */ /* compute the mmcon x mmcon block matrix S and e_j */ /* Note that S is symmetric, therefore its computation can be * sped up by computing only the upper part and then reusing * it for the lower one. */ for(j=mcon; j<m; ++j){ int mmconxUsz=mmcon*Usz; nnz=sba_crsm_col_elmidxs(&idxij, j, rcidxs, rcsubs); /* find nonzero Y_ij, i=0...n-1 */ /* compute all Y_ij = W_ij (V*_i)^-1 for a *fixed* j. * To save memory, the block matrix consisting of the Y_ij * is not stored. Instead, only a block column of this matrix * is computed & used at each time: For each j, all nonzero * Y_ij are computed in Yj and then used in the calculations * involving S_jk and e_j. * Recall that W_ij is cnp x pnp and (V*_i) is pnp x pnp */ for(i=0; i<nnz; ++i){ /* set ptr3 to point to (V*_i)^-1, actual row number in rcsubs[i] */ ptr3=V + rcsubs[i]*Vsz; /* set ptr1 to point to Y_ij, actual row number in rcsubs[i] */ ptr1=Yj + i*Ysz; /* set ptr2 to point to W_ij resp. */ ptr2=W + idxij.val[rcidxs[i]]*Wsz; /* compute W_ij (V*_i)^-1 and store it in Y_ij. * Recall that only the lower triangle of (V*_i)^-1 is stored */ for(ii=0; ii<cnp; ++ii){ ptr4=ptr2+ii*pnp; for(jj=0; jj<pnp; ++jj){ for(k=0, sum=0.0; k<=jj; ++k) sum+=ptr4[k]*ptr3[jj*pnp+k]; //ptr2[ii*pnp+k]*ptr3[jj*pnp+k]; for( ; k<pnp; ++k) sum+=ptr4[k]*ptr3[k*pnp+jj]; //ptr2[ii*pnp+k]*ptr3[k*pnp+jj]; ptr1[ii*pnp+jj]=sum; } } } /* compute the UPPER TRIANGULAR PART of S */ for(k=j; k<m; ++k){ // j>=mcon /* compute \sum_i Y_ij W_ik^T in YWt. Note that for an off-diagonal block defined by j, k * YWt (and thus S_jk) is nonzero only if there exists a point that is visible in both the * j-th and k-th images */ /* Recall that Y_ij is cnp x pnp and W_ik is cnp x pnp */ _dblzero(YWt, YWtsz); /* clear YWt */ for(i=0; i<nnz; ++i){ register double *pYWt; /* find the min and max column indices of the elements in row i (actually rcsubs[i]) * and make sure that k falls within them. This test handles W_ik's which are * certain to be zero without bothering to call sba_crsm_elmidx() */ ii=idxij.colidx[idxij.rowptr[rcsubs[i]]]; jj=idxij.colidx[idxij.rowptr[rcsubs[i]+1]-1]; if(k<ii || k>jj) continue; /* W_ik == 0 */ /* set ptr2 to point to W_ik */ l=sba_crsm_elmidxp(&idxij, rcsubs[i], k, j, rcidxs[i]); //l=sba_crsm_elmidx(&idxij, rcsubs[i], k); if(l==-1) continue; /* W_ik == 0 */ ptr2=W + idxij.val[l]*Wsz; /* set ptr1 to point to Y_ij, actual row number in rcsubs[i] */ ptr1=Yj + i*Ysz; for(ii=0; ii<cnp; ++ii){ ptr3=ptr1+ii*pnp; pYWt=YWt+ii*cnp; for(jj=0; jj<cnp; ++jj){ ptr4=ptr2+jj*pnp; for(l=0, sum=0.0; l<pnp; ++l) sum+=ptr3[l]*ptr4[l]; //ptr1[ii*pnp+l]*ptr2[jj*pnp+l]; pYWt[jj]+=sum; //YWt[ii*cnp+jj]+=sum; } } } /* since the linear system involving S is solved with lapack, * it is preferable to store S in column major (i.e. fortran) * order, so as to avoid unecessary transposing/copying. */#if MAT_STORAGE==COLUMN_MAJOR ptr2=S + (k-mcon)*mmconxUsz + (j-mcon)*cnp; // set ptr2 to point to the beginning of block j,k in S#else ptr2=S + (j-mcon)*mmconxUsz + (k-mcon)*cnp; // set ptr2 to point to the beginning of block j,k in S#endif if(j!=k){ /* Kronecker */ for(ii=0; ii<cnp; ++ii, ptr2+=Sdim) for(jj=0; jj<cnp; ++jj) ptr2[jj]=#if MAT_STORAGE==COLUMN_MAJOR -YWt[jj*cnp+ii];#else -YWt[ii*cnp+jj];#endif } else{ ptr1=U + j*Usz; // set ptr1 to point to U_j for(ii=0; ii<cnp; ++ii, ptr2+=Sdim) for(jj=0; jj<cnp; ++jj) ptr2[jj]=#if MAT_STORAGE==COLUMN_MAJOR ptr1[jj*cnp+ii] - YWt[jj*cnp+ii];#else ptr1[ii*cnp+jj] - YWt[ii*cnp+jj];#endif } } /* copy the LOWER TRIANGULAR PART of S from the upper one */ for(k=mcon; k<j; ++k){#if MAT_STORAGE==COLUMN_MAJOR ptr1=S + (k-mcon)*mmconxUsz + (j-mcon)*cnp; // set ptr1 to point to the beginning of block j,k in S ptr2=S + (j-mcon)*mmconxUsz + (k-mcon)*cnp; // set ptr2 to point to the beginning of block k,j in S#else ptr1=S + (j-mcon)*mmconxUsz + (k-mcon)*cnp; // set ptr1 to point to the beginning of block j,k in S ptr2=S + (k-mcon)*mmconxUsz + (j-mcon)*cnp; // set ptr2 to point to the beginning of block k,j in S#endif for(ii=0; ii<cnp; ++ii, ptr1+=Sdim) for(jj=0, ptr3=ptr2+ii; jj<cnp; ++jj, ptr3+=Sdim) ptr1[jj]=*ptr3; } /* compute e_j=ea_j - \sum_i Y_ij eb_i */ /* Recall that Y_ij is cnp x pnp and eb_i is pnp x 1 */ ptr1=E + j*easz; // set ptr1 to point to e_j for(i=0; i<nnz; ++i){ /* set ptr2 to point to Y_ij, actual row number in rcsubs[i] */ ptr2=Yj + i*Ysz; /* set ptr3 to point to eb_i */ ptr3=eb + rcsubs[i]*ebsz; for(ii=0; ii<cnp; ++ii){ ptr4=ptr2+ii*pnp; for(jj=0, sum=0.0; jj<pnp; ++jj) sum+=ptr4[jj]*ptr3[jj]; //ptr2[ii*pnp+jj]*ptr3[jj]; ptr1[ii]+=sum; } } ptr2=ea + j*easz; // set ptr2 to point to ea_j for(i=0; i<easz; ++i) ptr1[i]=ptr2[i] - ptr1[i]; }#if 0 if(verbose>1){ /* count the nonzeros in S */ for(i=ii=0; i<Sdim*Sdim; ++i) if(S[i]!=0.0) ++ii; printf("\nS density: %.5g\n", ((double)ii)/(Sdim*Sdim)); fflush(stdout); }#endif /* solve the linear system S dpa = E to compute the da_j. * * Note that if MAT_STORAGE==1 S is modified in the following call; * this is OK since S is recomputed for each iteration */ //issolved=sba_Axb_LU(S, E+mcon*cnp, dpa+mcon*cnp, Sdim, MAT_STORAGE); linsolver=sba_Axb_LU; issolved=sba_Axb_Chol(S, E+mcon*cnp, dpa+mcon*cnp, Sdim, MAT_STORAGE); linsolver=sba_Axb_Chol; //issolved=sba_Axb_BK(S, E+mcon*cnp, dpa+mcon*cnp, Sdim, MAT_STORAGE); linsolver=sba_Axb_BK; //issolved=sba_Axb_QRnoQ(S, E+mcon*cnp, dpa+mcon*cnp, Sdim, MAT_STORAGE); linsolver=sba_Axb_QRnoQ; //issolved=sba_Axb_QR(S, E+mcon*cnp, dpa+mcon*cnp, Sdim, MAT_STORAGE); linsolver=sba_Axb_QR; //issolved=sba_Axb_SVD(S, E+mcon*cnp, dpa+mcon*cnp, Sdim, MAT_STORAGE); linsolver=sba_Axb_SVD; //issolved=sba_Axb_CG(S, E+mcon*cnp, dpa+mcon*cnp, Sdim, (3*Sdim)/2, 1E-10, SBA_CG_JACOBI, MAT_STORAGE); linsolver=(PLS)sba_Axb_CG; ++nlss; _dblzero(dpa, mcon*cnp); /* no change for the first mcon camera params */ if(issolved){ /* compute the db_i */ for(i=0; i<n; ++i){ ptr1=dpb + i*ebsz; // set ptr1 to point to db_i /* compute \sum_j W_ij^T da_j */ /* Recall that W_ij is cnp x pnp and da_j is cnp x 1 */ _dblzero(Wtda, Wtdasz); /* clear Wtda */ nnz=sba_crsm_row_elmidxs(&idxij, i, rcidxs, rcsubs); /* find nonzero W_ij, j=0...m-1 */ for(j=0; j<nnz; ++j){ /* set ptr2 to point to W_ij, actual column number in rcsubs[j] */ if(rcsubs[j]<mcon) continue; /* W_ij is zero */ ptr2=W + idxij.val[rcidxs[j]]*Wsz; /* set ptr3 to point to da_j */ ptr3=dpa + rcsubs[j]*cnp; for(ii=0; ii<pnp; ++ii){ ptr4=ptr2+ii; for(jj=0, sum=0.0; jj<cnp; ++jj) sum+=ptr4[jj*pnp]*ptr3[jj]; //ptr2[jj*pnp+ii]*ptr3[jj]; Wtda[ii]+=sum; } } /* compute eb_i - \sum_j W_ij^T da_j = eb_i - Wtda in Wtda */ ptr2=eb + i*ebsz; // set ptr2 to point to eb_i for(ii=0; ii<pnp; ++ii) Wtda[ii]=ptr2[ii] - Wtda[ii]; /* compute the product (V*_i)^-1 Wtda = (V*_i)^-1 (eb_i - \sum_j W_ij^T da_j). * Recall that only the lower triangle of (V*_i)^-1 is stored */ ptr2=V + i*Vsz; // set ptr2 to point to (V*_i)^-1 for(ii=0; ii<pnp; ++ii){ for(jj=0, sum=0.0; jj<=ii; ++jj) sum+=ptr2[ii*pnp+jj]*Wtda[jj]; for( ; jj<pnp; ++jj) sum+=ptr2[jj*pnp+ii]*Wtda[jj]; ptr1[ii]=sum; } } /* parameter vector updates are now in dpa, dpb */ /* compute p's new estimate and ||dp||^2 */ for(i=0, dp_L2=0.0; i<nvars; ++i){ pdp[i]=p[i] + (tmp=dp[i]); dp_L2+=tmp*tmp; } //dp_L2=sqrt(dp_L2); if(dp_L2<=eps2_sq*p_L2){ /* relative change in p is small, stop */ //if(dp_L2<=eps2*(p_L2 + eps2)){ /* relative change in p is small, stop */ stop=2; break; } if(dp_L2>=(p_L2+eps2)/SBA_EPSILON_SQ){ /* almost singular */ //if(dp_L2>=(p_L2+eps2)/SBA_EPSILON){ /* almost singular */ fprintf(stderr, "SBA: the matrix of the augmented normal equations is almost singular in sba_motstr_levmar_x(),\n" " minimization should be restarted from the current solution with an increased damping term\n"); retval=SBA_ERROR; goto freemem_and_return; } (*func)(pdp, &idxij, rcidxs, rcsubs, hx, adata); ++nfev; /* evaluate function at p + dp */ if(verbose>1) printf("mean reprojection error %g\n", sba_mean_repr_error(n, mnp, x, hx, &idxij, rcidxs, rcsubs)); /* ### compute ||e(pdp)||_2 */ if(covx==NULL) pdp_eL2=nrmL2xmy(hx, x, hx, nobs); /* hx=x-hx, pdp_eL2=||hx|| */ else pdp_eL2=nrmCxmy(hx, x, hx, wght, mnp, nvis); /* hx=wght*(x-hx), pdp_eL2=||hx|| */ if(!SBA_FINITE(pdp_eL2)){ if(verbose) /* identify the offending point projection */ sba_print_inf(hx, m, mnp, &idxij, rcidxs, rcsubs); stop=7; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -