/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // Intel License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "precomp.hpp" #include #include #include void icvReconstructPoints4DStatus(CvMat** projPoints, CvMat **projMatrs, CvMat** presPoints, CvMat *points4D,int numImages,CvMat **projError=0); /* Valery Mosyagin */ /* If you want to save internal debug info to files uncomment next lines and set paths to files if need */ /* Note these file may be very large */ /* #define TRACK_BUNDLE #define TRACK_BUNDLE_FILE "d:\\test\\bundle.txt" #define TRACK_BUNDLE_FILE_JAC "d:\\test\\bundle.txt" #define TRACK_BUNDLE_FILE_JACERRPROJ "d:\\test\\JacErrProj.txt" #define TRACK_BUNDLE_FILE_JACERRPNT "d:\\test\\JacErrPoint.txt" #define TRACK_BUNDLE_FILE_MATRW "d:\\test\\matrWt.txt" #define TRACK_BUNDLE_FILE_DELTAP "d:\\test\\deltaP.txt" */ #define TRACK_BUNDLE_FILE "d:\\test\\bundle.txt" void cvOptimizeLevenbergMarquardtBundle( CvMat** projMatrs, CvMat** observProjPoints, CvMat** pointsPres, int numImages, CvMat** resultProjMatrs, CvMat* resultPoints4D,int maxIter,double epsilon ); /* ============== Bundle adjustment optimization ================= */ static void icvComputeDerivateProj(CvMat *points4D,CvMat *projMatr, CvMat *status, CvMat *derivProj) { /* Compute derivate for given projection matrix points and status of points */ CV_FUNCNAME( "icvComputeDerivateProj" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( points4D == 0 || projMatr == 0 || status == 0 || derivProj == 0) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } if( !CV_IS_MAT(points4D) ) { CV_ERROR( CV_StsUnsupportedFormat, "points4D must be a matrix 4xN" ); } /* Compute number of points */ int numPoints; numPoints = points4D->cols; if( numPoints < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of points4D must be more than zero" ); } if( points4D->rows != 4 ) { CV_ERROR( CV_StsOutOfRange, "Number of coordinates of points4D must be 4" ); } if( !CV_IS_MAT(projMatr) ) { CV_ERROR( CV_StsUnsupportedFormat, "projMatr must be a matrix 3x4" ); } if( projMatr->rows != 3 || projMatr->cols != 4 ) { CV_ERROR( CV_StsOutOfRange, "Size of projection matrix (projMatr) must be 3x4" ); } if( !CV_IS_MAT(status) ) { CV_ERROR( CV_StsUnsupportedFormat, "Status must be a matrix 1xN" ); } if( status->rows != 1 || status->cols != numPoints ) { CV_ERROR( CV_StsOutOfRange, "Size of status of points must be 1xN" ); } if( !CV_IS_MAT(derivProj) ) { CV_ERROR( CV_StsUnsupportedFormat, "derivProj must be a matrix VisN x 12" ); } if( derivProj->cols != 12 ) { CV_ERROR( CV_StsOutOfRange, "derivProj must be a matrix VisN x 12" ); } /* ----- End test ----- */ /* Allocate memory for derivates */ double p[12]; /* Copy projection matrix */ for(int i = 0; i < 12; i++ ) { p[i] = cvmGet(projMatr,i/4,i%4); } /* Fill deriv matrix */ int currVisPoint; int currPoint; currVisPoint = 0; for( currPoint = 0; currPoint < numPoints; currPoint++ ) { if( cvmGet(status,0,currPoint) > 0 ) { double X[4]; X[0] = cvmGet(points4D,0,currVisPoint); X[1] = cvmGet(points4D,1,currVisPoint); X[2] = cvmGet(points4D,2,currVisPoint); X[3] = cvmGet(points4D,3,currVisPoint); /* Compute derivate for this point */ double piX[3]; piX[0] = X[0]*p[0] + X[1]*p[1] + X[2]*p[2] + X[3]*p[3]; piX[1] = X[0]*p[4] + X[1]*p[5] + X[2]*p[6] + X[3]*p[7]; piX[2] = X[0]*p[8] + X[1]*p[9] + X[2]*p[10] + X[3]*p[11]; /* fill derivate by point */ double tmp3 = 1/(piX[2]*piX[2]); double tmp1 = -piX[0]*tmp3; double tmp2 = -piX[1]*tmp3; /* fill derivate by projection matrix */ for(int i = 0; i < 4; i++ ) { /* derivate for x */ cvmSet(derivProj,currVisPoint*2,i,X[i]/piX[2]);//x' p1i cvmSet(derivProj,currVisPoint*2,4+i,0);//x' p1i cvmSet(derivProj,currVisPoint*2,8+i,X[i]*tmp1);//x' p3i /* derivate for y */ cvmSet(derivProj,currVisPoint*2+1,i,0);//y' p2i cvmSet(derivProj,currVisPoint*2+1,4+i,X[i]/piX[2]);//y' p2i cvmSet(derivProj,currVisPoint*2+1,8+i,X[i]*tmp2);//y' p3i } currVisPoint++; } } if( derivProj->rows != currVisPoint * 2 ) { CV_ERROR( CV_StsOutOfRange, "derivProj must be a matrix 2VisN x 12" ); } __END__; return; } /*======================================================================================*/ static void icvComputeDerivateProjAll(CvMat *points4D, CvMat **projMatrs, CvMat **pointPres, int numImages,CvMat **projDerives) { CV_FUNCNAME( "icvComputeDerivateProjAll" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" ); } if( projMatrs == 0 || pointPres == 0 || projDerives == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } /* ----- End test ----- */ int currImage; for( currImage = 0; currImage < numImages; currImage++ ) { icvComputeDerivateProj(points4D,projMatrs[currImage], pointPres[currImage], projDerives[currImage]); } __END__; return; } /*======================================================================================*/ static void icvComputeDerivatePoints(CvMat *points4D,CvMat *projMatr, CvMat *presPoints, CvMat *derivPoint) { CV_FUNCNAME( "icvComputeDerivatePoints" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( points4D == 0 || projMatr == 0 || presPoints == 0 || derivPoint == 0) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } if( !CV_IS_MAT(points4D) ) { CV_ERROR( CV_StsUnsupportedFormat, "points4D must be a matrix N x 4" ); } int numPoints; numPoints = presPoints->cols; if( numPoints < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of points must be more than zero" ); } if( points4D->rows != 4 ) { CV_ERROR( CV_StsOutOfRange, "points4D must be a matrix N x 4" ); } if( !CV_IS_MAT(projMatr) ) { CV_ERROR( CV_StsUnsupportedFormat, "projMatr must be a matrix 3x4" ); } if( projMatr->rows != 3 || projMatr->cols != 4 ) { CV_ERROR( CV_StsOutOfRange, "Size of projection matrix (projMatr) must be 3x4" ); } if( !CV_IS_MAT(presPoints) ) { CV_ERROR( CV_StsUnsupportedFormat, "Status must be a matrix 1xN" ); } if( presPoints->rows != 1 || presPoints->cols != numPoints ) { CV_ERROR( CV_StsOutOfRange, "Size of presPoints status must be 1xN" ); } if( !CV_IS_MAT(derivPoint) ) { CV_ERROR( CV_StsUnsupportedFormat, "derivPoint must be a matrix 2 x 4VisNum" ); } /* ----- End test ----- */ /* Compute derivates by points */ double p[12]; for(int i = 0; i < 12; i++ ) { p[i] = cvmGet(projMatr,i/4,i%4); } int currVisPoint; int currProjPoint; currVisPoint = 0; for( currProjPoint = 0; currProjPoint < numPoints; currProjPoint++ ) { if( cvmGet(presPoints,0,currProjPoint) > 0 ) { double X[4]; X[0] = cvmGet(points4D,0,currProjPoint); X[1] = cvmGet(points4D,1,currProjPoint); X[2] = cvmGet(points4D,2,currProjPoint); X[3] = cvmGet(points4D,3,currProjPoint); double piX[3]; piX[0] = X[0]*p[0] + X[1]*p[1] + X[2]*p[2] + X[3]*p[3]; piX[1] = X[0]*p[4] + X[1]*p[5] + X[2]*p[6] + X[3]*p[7]; piX[2] = X[0]*p[8] + X[1]*p[9] + X[2]*p[10] + X[3]*p[11]; double tmp3 = 1/(piX[2]*piX[2]); for(int j = 0; j < 2; j++ )//for x and y { for(int i = 0; i < 4; i++ )// for X,Y,Z,W { cvmSet( derivPoint, j, currVisPoint*4+i, (p[j*4+i]*piX[2]-p[8+i]*piX[j]) * tmp3 ); } } currVisPoint++; } } if( derivPoint->rows != 2 || derivPoint->cols != currVisPoint*4 ) { CV_ERROR( CV_StsUnsupportedFormat, "derivPoint must be a matrix 2 x 4VisNum" ); } __END__; return; } /*======================================================================================*/ static void icvComputeDerivatePointsAll(CvMat *points4D, CvMat **projMatrs, CvMat **pointPres, int numImages,CvMat **pointDerives) { CV_FUNCNAME( "icvComputeDerivatePointsAll" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" ); } if( projMatrs == 0 || pointPres == 0 || pointDerives == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } /* ----- End test ----- */ int currImage; for( currImage = 0; currImage < numImages; currImage++ ) { icvComputeDerivatePoints(points4D, projMatrs[currImage], pointPres[currImage], pointDerives[currImage]); } __END__; return; } /*======================================================================================*/ static void icvComputeMatrixVAll(int numImages,CvMat **pointDeriv,CvMat **presPoints, CvMat **matrV) { int *shifts = 0; CV_FUNCNAME( "icvComputeMatrixVAll" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" ); } if( pointDeriv == 0 || presPoints == 0 || matrV == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } /* !!! not tested all parameters */ /* ----- End test ----- */ /* Compute all matrices U */ int currImage; int currPoint; int numPoints; numPoints = presPoints[0]->cols; CV_CALL(shifts = (int*)cvAlloc(sizeof(int)*numImages)); memset(shifts,0,sizeof(int)*numImages); for( currPoint = 0; currPoint < numPoints; currPoint++ )//For each point (matrix V) { int i,j; for( i = 0; i < 4; i++ ) { for( j = 0; j < 4; j++ ) { double sum = 0; for( currImage = 0; currImage < numImages; currImage++ ) { if( cvmGet(presPoints[currImage],0,currPoint) > 0 ) { sum += cvmGet(pointDeriv[currImage],0,shifts[currImage]*4+i) * cvmGet(pointDeriv[currImage],0,shifts[currImage]*4+j); sum += cvmGet(pointDeriv[currImage],1,shifts[currImage]*4+i) * cvmGet(pointDeriv[currImage],1,shifts[currImage]*4+j); } } cvmSet(matrV[currPoint],i,j,sum); } } /* shift position of visible points */ for( currImage = 0; currImage < numImages; currImage++ ) { if( cvmGet(presPoints[currImage],0,currPoint) > 0 ) { shifts[currImage]++; } } } __END__; cvFree( &shifts); return; } /*======================================================================================*/ static void icvComputeMatrixUAll(int numImages,CvMat **projDeriv,CvMat** matrU) { CV_FUNCNAME( "icvComputeMatrixVAll" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" ); } if( projDeriv == 0 || matrU == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } /* !!! Not tested all input parameters */ /* ----- End test ----- */ /* Compute matrices V */ int currImage; for( currImage = 0; currImage < numImages; currImage++ ) { cvMulTransposed(projDeriv[currImage],matrU[currImage],1); } __END__; return; } /*======================================================================================*/ static void icvComputeMatrixW(int numImages, CvMat **projDeriv, CvMat **pointDeriv, CvMat **presPoints, CvMat *matrW) { CV_FUNCNAME( "icvComputeMatrixW" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" ); } if( projDeriv == 0 || pointDeriv == 0 || presPoints == 0 || matrW == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } int numPoints; numPoints = presPoints[0]->cols; if( numPoints < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of points must more than zero" ); } if( !CV_IS_MAT(matrW) ) { CV_ERROR( CV_StsUnsupportedFormat, "matrW must be a matrix 12NumIm x 4NumPnt" ); } if( matrW->rows != numImages*12 || matrW->cols != numPoints*4 ) { CV_ERROR( CV_StsOutOfRange, "matrW must be a matrix 12NumIm x 4NumPnt" ); } /* !!! Not tested all input parameters */ /* ----- End test ----- */ /* Compute number of points */ /* Compute matrix W using derivate proj and points */ int currImage; for( currImage = 0; currImage < numImages; currImage++ ) { for( int currLine = 0; currLine < 12; currLine++ ) { int currVis = 0; for( int currPoint = 0; currPoint < numPoints; currPoint++ ) { if( cvmGet(presPoints[currImage],0,currPoint) > 0 ) { for( int currCol = 0; currCol < 4; currCol++ ) { double sum; sum = cvmGet(projDeriv[currImage],currVis*2+0,currLine) * cvmGet(pointDeriv[currImage],0,currVis*4+currCol); sum += cvmGet(projDeriv[currImage],currVis*2+1,currLine) * cvmGet(pointDeriv[currImage],1,currVis*4+currCol); cvmSet(matrW,currImage*12+currLine,currPoint*4+currCol,sum); } currVis++; } else {/* set all sub elements to zero */ for( int currCol = 0; currCol < 4; currCol++ ) { cvmSet(matrW,currImage*12+currLine,currPoint*4+currCol,0); } } } } } #ifdef TRACK_BUNDLE { FILE *file; file = fopen( TRACK_BUNDLE_FILE_MATRW ,"w"); int currPoint,currImage; for( currPoint = 0; currPoint < numPoints; currPoint++ ) { fprintf(file,"\nPoint=%d\n",currPoint); int currRow; for( currRow = 0; currRow < 4; currRow++ ) { for( currImage = 0; currImage< numImages; currImage++ ) { int i; for( i = 0; i < 12; i++ ) { double val = cvmGet(matrW, currImage * 12 + i, currPoint * 4 + currRow); fprintf(file,"%lf ",val); } } fprintf(file,"\n"); } } fclose(file); } #endif __END__; return; } /*======================================================================================*/ /* Compute jacobian mult projection matrices error */ static void icvComputeJacErrorProj(int numImages,CvMat **projDeriv,CvMat **projErrors,CvMat *jacProjErr ) { CV_FUNCNAME( "icvComputeJacErrorProj" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" ); } if( projDeriv == 0 || projErrors == 0 || jacProjErr == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } if( !CV_IS_MAT(jacProjErr) ) { CV_ERROR( CV_StsUnsupportedFormat, "jacProjErr must be a matrix 12NumIm x 1" ); } if( jacProjErr->rows != numImages*12 || jacProjErr->cols != 1 ) { CV_ERROR( CV_StsOutOfRange, "jacProjErr must be a matrix 12NumIm x 1" ); } /* !!! Not tested all input parameters */ /* ----- End test ----- */ int currImage; for( currImage = 0; currImage < numImages; currImage++ ) { for( int currCol = 0; currCol < 12; currCol++ ) { int num = projDeriv[currImage]->rows; double sum = 0; for( int i = 0; i < num; i++ ) { sum += cvmGet(projDeriv[currImage],i,currCol) * cvmGet(projErrors[currImage],i%2,i/2); } cvmSet(jacProjErr,currImage*12+currCol,0,sum); } } #ifdef TRACK_BUNDLE { FILE *file; file = fopen( TRACK_BUNDLE_FILE_JACERRPROJ ,"w"); int currImage; for( currImage = 0; currImage < numImages; currImage++ ) { fprintf(file,"\nImage=%d\n",currImage); int currRow; for( currRow = 0; currRow < 12; currRow++ ) { double val = cvmGet(jacProjErr, currImage * 12 + currRow, 0); fprintf(file,"%lf\n",val); } fprintf(file,"\n"); } fclose(file); } #endif __END__; return; } /*======================================================================================*/ /* Compute jacobian mult points error */ static void icvComputeJacErrorPoint(int numImages,CvMat **pointDeriv,CvMat **projErrors, CvMat **presPoints,CvMat *jacPointErr ) { int *shifts = 0; CV_FUNCNAME( "icvComputeJacErrorPoint" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" ); } if( pointDeriv == 0 || projErrors == 0 || presPoints == 0 || jacPointErr == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } int numPoints; numPoints = presPoints[0]->cols; if( numPoints < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of points must more than zero" ); } if( !CV_IS_MAT(jacPointErr) ) { CV_ERROR( CV_StsUnsupportedFormat, "jacPointErr must be a matrix 4NumPnt x 1" ); } if( jacPointErr->rows != numPoints*4 || jacPointErr->cols != 1 ) { CV_ERROR( CV_StsOutOfRange, "jacPointErr must be a matrix 4NumPnt x 1" ); } /* !!! Not tested all input parameters */ /* ----- End test ----- */ int currImage; int currPoint; CV_CALL(shifts = (int*)cvAlloc(sizeof(int)*numImages)); memset(shifts,0,sizeof(int)*numImages); for( currPoint = 0; currPoint < numPoints; currPoint++ ) { for( int currCoord = 0; currCoord < 4; currCoord++ ) { double sum = 0; { int currVis = 0; for( currImage = 0; currImage < numImages; currImage++ ) { if( cvmGet(presPoints[currImage],0,currPoint) > 0 ) { sum += cvmGet(pointDeriv[currImage],0,shifts[currImage]*4+currCoord) * cvmGet(projErrors[currImage],0,shifts[currImage]);//currVis); sum += cvmGet(pointDeriv[currImage],1,shifts[currImage]*4+currCoord) * cvmGet(projErrors[currImage],1,shifts[currImage]);//currVis); currVis++; } } } cvmSet(jacPointErr,currPoint*4+currCoord,0,sum); } /* Increase shifts */ for( currImage = 0; currImage < numImages; currImage++ ) { if( cvmGet(presPoints[currImage],0,currPoint) > 0 ) { shifts[currImage]++; } } } #ifdef TRACK_BUNDLE { FILE *file; file = fopen(TRACK_BUNDLE_FILE_JACERRPNT,"w"); int currPoint; for( currPoint = 0; currPoint < numPoints; currPoint++ ) { fprintf(file,"\nPoint=%d\n",currPoint); int currRow; for( currRow = 0; currRow < 4; currRow++ ) { double val = cvmGet(jacPointErr, currPoint * 4 + currRow, 0); fprintf(file,"%lf\n",val); } fprintf(file,"\n"); } fclose(file); } #endif __END__; cvFree( &shifts); } /*======================================================================================*/ /* Reconstruct 4D points using status */ void icvReconstructPoints4DStatus(CvMat** projPoints, CvMat **projMatrs, CvMat** presPoints, CvMat *points4D,int numImages,CvMat **projError) { double* matrA_dat = 0; double* matrW_dat = 0; CV_FUNCNAME( "icvReconstructPoints4DStatus" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 2 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must be more than one" ); } if( projPoints == 0 || projMatrs == 0 || presPoints == 0 || points4D == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } int numPoints; numPoints = points4D->cols; if( numPoints < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of points4D must be more than zero" ); } if( points4D->rows != 4 ) { CV_ERROR( CV_StsOutOfRange, "Points must have 4 cordinates" ); } /* !!! Not tested all input parameters */ /* ----- End test ----- */ int currImage; int currPoint; /* Allocate maximum data */ { double matrV_dat[4*4]; CvMat matrV = cvMat(4,4,CV_64F,matrV_dat); CV_CALL(matrA_dat = (double*)cvAlloc(3*numImages * 4 * sizeof(double))); CV_CALL(matrW_dat = (double*)cvAlloc(3*numImages * 4 * sizeof(double))); /* reconstruct each point */ for( currPoint = 0; currPoint < numPoints; currPoint++ ) { /* Reconstruct current point */ /* Define number of visible projections */ int numVisProj = 0; for( currImage = 0; currImage < numImages; currImage++ ) { if( cvmGet(presPoints[currImage],0,currPoint) > 0 ) { numVisProj++; } } if( numVisProj < 2 ) { /* This point can't be reconstructed */ continue; } /* Allocate memory and create matrices */ CvMat matrA; matrA = cvMat(3*numVisProj,4,CV_64F,matrA_dat); CvMat matrW; matrW = cvMat(3*numVisProj,4,CV_64F,matrW_dat); int currVisProj = 0; for( currImage = 0; currImage < numImages; currImage++ )/* For each view */ { if( cvmGet(presPoints[currImage],0,currPoint) > 0 ) { double x,y; x = cvmGet(projPoints[currImage],0,currPoint); y = cvmGet(projPoints[currImage],1,currPoint); for( int k = 0; k < 4; k++ ) { matrA_dat[currVisProj*12 + k] = x * cvmGet(projMatrs[currImage],2,k) - cvmGet(projMatrs[currImage],0,k); matrA_dat[currVisProj*12+4 + k] = y * cvmGet(projMatrs[currImage],2,k) - cvmGet(projMatrs[currImage],1,k); matrA_dat[currVisProj*12+8 + k] = x * cvmGet(projMatrs[currImage],1,k) - y * cvmGet(projMatrs[currImage],0,k); } currVisProj++; } } /* Solve system for current point */ { cvSVD(&matrA,&matrW,0,&matrV,CV_SVD_V_T); /* Copy computed point */ cvmSet(points4D,0,currPoint,cvmGet(&matrV,3,0));//X cvmSet(points4D,1,currPoint,cvmGet(&matrV,3,1));//Y cvmSet(points4D,2,currPoint,cvmGet(&matrV,3,2));//Z cvmSet(points4D,3,currPoint,cvmGet(&matrV,3,3));//W } } } {/* Compute projection error */ for( currImage = 0; currImage < numImages; currImage++ ) { CvMat point4D; CvMat point3D; double point3D_dat[3]; point3D = cvMat(3,1,CV_64F,point3D_dat); int numVis = 0; double totalError = 0; for(int curPoint = 0; curPoint < numPoints; curPoint++ ) { if( cvmGet(presPoints[currImage],0,curPoint) > 0) { double dx,dy; cvGetCol(points4D,&point4D,curPoint); cvmMul(projMatrs[currImage],&point4D,&point3D); double w = point3D_dat[2]; double x = point3D_dat[0] / w; double y = point3D_dat[1] / w; dx = cvmGet(projPoints[currImage],0,curPoint) - x; dy = cvmGet(projPoints[currImage],1,curPoint) - y; if( projError ) { cvmSet(projError[currImage],0,curPoint,dx); cvmSet(projError[currImage],1,curPoint,dy); } totalError += sqrt(dx*dx+dy*dy); numVis++; } } //double meanError = totalError / (double)numVis; } } __END__; cvFree( &matrA_dat); cvFree( &matrW_dat); return; } /*======================================================================================*/ static void icvProjPointsStatusFunc( int numImages, CvMat *points4D, CvMat **projMatrs, CvMat **pointsPres, CvMat **projPoints) { CV_FUNCNAME( "icvProjPointsStatusFunc" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must be more than zero" ); } if( points4D == 0 || projMatrs == 0 || pointsPres == 0 || projPoints == 0 ) { CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" ); } { int numPoints; numPoints = points4D->cols; if( numPoints < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of points4D must be more than zero" ); } if( points4D->rows != 4 ) { CV_ERROR( CV_StsOutOfRange, "Points must have 4 cordinates" ); } /* !!! Not tested all input parameters */ /* ----- End test ----- */ CvMat point4D; CvMat point3D; double point4D_dat[4]; double point3D_dat[3]; point4D = cvMat(4,1,CV_64F,point4D_dat); point3D = cvMat(3,1,CV_64F,point3D_dat); #ifdef TRACK_BUNDLE { FILE *file; file = fopen( TRACK_BUNDLE_FILE ,"a"); fprintf(file,"\n----- test 14.01 icvProjPointsStatusFunc -----\n"); fclose(file); } #endif int currImage; for( currImage = 0; currImage < numImages; currImage++ ) { /* Get project matrix */ /* project visible points using current projection matrix */ int currVisPoint = 0; for( int currPoint = 0; currPoint < numPoints; currPoint++ ) { if( cvmGet(pointsPres[currImage],0,currPoint) > 0 ) { /* project current point */ cvGetSubRect(points4D,&point4D,cvRect(currPoint,0,1,4)); #ifdef TRACK_BUNDLE { FILE *file; file = fopen( TRACK_BUNDLE_FILE ,"a"); fprintf(file,"\n----- test 14.02 point4D (%lf, %lf, %lf, %lf) -----\n", cvmGet(&point4D,0,0), cvmGet(&point4D,1,0), cvmGet(&point4D,2,0), cvmGet(&point4D,3,0)); fclose(file); } #endif cvmMul(projMatrs[currImage],&point4D,&point3D); double w = point3D_dat[2]; cvmSet(projPoints[currImage],0,currVisPoint,point3D_dat[0]/w); cvmSet(projPoints[currImage],1,currVisPoint,point3D_dat[1]/w); #ifdef TRACK_BUNDLE { FILE *file; file = fopen( TRACK_BUNDLE_FILE ,"a"); fprintf(file,"\n----- test 14.03 (%lf, %lf, %lf) -> (%lf, %lf)-----\n", point3D_dat[0], point3D_dat[1], point3D_dat[2], point3D_dat[0]/w, point3D_dat[1]/w ); fclose(file); } #endif currVisPoint++; } } } } __END__; } /*======================================================================================*/ static void icvFreeMatrixArray(CvMat ***matrArray,int numMatr) { /* Free each matrix */ int currMatr; if( *matrArray != 0 ) {/* Need delete */ for( currMatr = 0; currMatr < numMatr; currMatr++ ) { cvReleaseMat((*matrArray)+currMatr); } cvFree( matrArray); } return; } /*======================================================================================*/ static void *icvClearAlloc(int size) { void *ptr = 0; CV_FUNCNAME( "icvClearAlloc" ); __BEGIN__; if( size > 0 ) { CV_CALL(ptr = cvAlloc(size)); memset(ptr,0,size); } __END__; return ptr; } /*======================================================================================*/ #if 0 void cvOptimizeLevenbergMarquardtBundleWraper( CvMat** projMatrs, CvMat** observProjPoints, CvMat** pointsPres, int numImages, CvMat** resultProjMatrs, CvMat* resultPoints4D,int maxIter,double epsilon ) { /* Delete al sparse points */ int icvDeleteSparsInPoints( int numImages, CvMat **points, CvMat **status, CvMat *wasStatus)/* status of previous configuration */ } #endif /*======================================================================================*/ /* !!! may be useful to return norm of error */ /* !!! may be does not work correct with not all visible 4D points */ void cvOptimizeLevenbergMarquardtBundle( CvMat** projMatrs, CvMat** observProjPoints, CvMat** pointsPres, int numImages, CvMat** resultProjMatrs, CvMat* resultPoints4D,int maxIter,double epsilon ) { CvMat *vectorX_points4D = 0; CvMat **vectorX_projMatrs = 0; CvMat *newVectorX_points4D = 0; CvMat **newVectorX_projMatrs = 0; CvMat *changeVectorX_points4D = 0; CvMat *changeVectorX_projMatrs = 0; CvMat **observVisPoints = 0; CvMat **projVisPoints = 0; CvMat **errorProjPoints = 0; CvMat **DerivProj = 0; CvMat **DerivPoint = 0; CvMat *matrW = 0; CvMat **matrsUk = 0; CvMat **workMatrsUk = 0; CvMat **matrsVi = 0; CvMat *workMatrVi = 0; CvMat **workMatrsInvVi = 0; CvMat *jacProjErr = 0; CvMat *jacPointErr = 0; CvMat *matrTmpSys1 = 0; CvMat *matrSysDeltaP = 0; CvMat *vectTmpSys3 = 0; CvMat *vectSysDeltaP = 0; CvMat *deltaP = 0; CvMat *deltaM = 0; CvMat *vectTmpSysM = 0; int numPoints = 0; CV_FUNCNAME( "cvOptimizeLevenbergMarquardtBundle" ); __BEGIN__; /* ----- Test input params for errors ----- */ if( numImages < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of images must be more than zero" ); } if( maxIter < 1 || maxIter > 2000 ) { CV_ERROR( CV_StsOutOfRange, "Maximum number of iteration must be in [1..1000]" ); } if( epsilon < 0 ) { CV_ERROR( CV_StsOutOfRange, "Epsilon parameter must be >= 0" ); } if( !CV_IS_MAT(resultPoints4D) ) { CV_ERROR( CV_StsUnsupportedFormat, "resultPoints4D must be a matrix 4 x NumPnt" ); } numPoints = resultPoints4D->cols; if( numPoints < 1 ) { CV_ERROR( CV_StsOutOfRange, "Number of points must be more than zero" );//!!! } if( resultPoints4D->rows != 4 ) { CV_ERROR( CV_StsOutOfRange, "resultPoints4D must have 4 cordinates" ); } /* ----- End test ----- */ /* Optimization using bundle adjustment */ /* work with non visible points */ CV_CALL( vectorX_points4D = cvCreateMat(4,numPoints,CV_64F)); CV_CALL( vectorX_projMatrs = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages)); CV_CALL( newVectorX_points4D = cvCreateMat(4,numPoints,CV_64F)); CV_CALL( newVectorX_projMatrs = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages)); CV_CALL( changeVectorX_points4D = cvCreateMat(4,numPoints,CV_64F)); CV_CALL( changeVectorX_projMatrs = cvCreateMat(3,4,CV_64F)); /* ----- Test input params ----- */ for(int currImage = 0; currImage < numImages; currImage++ ) { /* Test size of input initial and result projection matrices */ if( !CV_IS_MAT(projMatrs[currImage]) ) { CV_ERROR( CV_StsUnsupportedFormat, "each of initial projMatrs must be a matrix 3 x 4" ); } if( projMatrs[currImage]->rows != 3 || projMatrs[currImage]->cols != 4 ) { CV_ERROR( CV_StsOutOfRange, "each of initial projMatrs must be a matrix 3 x 4" ); } if( !CV_IS_MAT(observProjPoints[currImage]) ) { CV_ERROR( CV_StsUnsupportedFormat, "each of observProjPoints must be a matrix 2 x NumPnts" ); } if( observProjPoints[currImage]->rows != 2 || observProjPoints[currImage]->cols != numPoints ) { CV_ERROR( CV_StsOutOfRange, "each of observProjPoints must be a matrix 2 x NumPnts" ); } if( !CV_IS_MAT(pointsPres[currImage]) ) { CV_ERROR( CV_StsUnsupportedFormat, "each of pointsPres must be a matrix 1 x NumPnt" ); } if( pointsPres[currImage]->rows != 1 || pointsPres[currImage]->cols != numPoints ) { CV_ERROR( CV_StsOutOfRange, "each of pointsPres must be a matrix 1 x NumPnt" ); } if( !CV_IS_MAT(resultProjMatrs[currImage]) ) { CV_ERROR( CV_StsUnsupportedFormat, "each of resultProjMatrs must be a matrix 3 x 4" ); } if( resultProjMatrs[currImage]->rows != 3 || resultProjMatrs[currImage]->cols != 4 ) { CV_ERROR( CV_StsOutOfRange, "each of resultProjMatrs must be a matrix 3 x 4" ); } } /* ----- End test ----- */ /* Copy projection matrices to vectorX0 */ for(int currImage = 0; currImage < numImages; currImage++ ) { CV_CALL( vectorX_projMatrs[currImage] = cvCreateMat(3,4,CV_64F)); CV_CALL( newVectorX_projMatrs[currImage] = cvCreateMat(3,4,CV_64F)); cvCopy(projMatrs[currImage],vectorX_projMatrs[currImage]); } /* Reconstruct points4D using projection matrices and status information */ icvReconstructPoints4DStatus(observProjPoints, projMatrs, pointsPres, vectorX_points4D, numImages); /* ----- Allocate memory for work matrices ----- */ /* Compute number of good points on each images */ CV_CALL( observVisPoints = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) ); CV_CALL( projVisPoints = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) ); CV_CALL( errorProjPoints = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) ); CV_CALL( DerivProj = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) ); CV_CALL( DerivPoint = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) ); CV_CALL( matrW = cvCreateMat(12*numImages,4*numPoints,CV_64F) ); CV_CALL( matrsUk = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) ); CV_CALL( workMatrsUk = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) ); CV_CALL( matrsVi = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numPoints) ); CV_CALL( workMatrVi = cvCreateMat(4,4,CV_64F) ); CV_CALL( workMatrsInvVi = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numPoints) ); CV_CALL( jacProjErr = cvCreateMat(12*numImages,1,CV_64F) ); CV_CALL( jacPointErr = cvCreateMat(4*numPoints,1,CV_64F) ); int i; for( i = 0; i < numPoints; i++ ) { CV_CALL( matrsVi[i] = cvCreateMat(4,4,CV_64F) ); CV_CALL( workMatrsInvVi[i] = cvCreateMat(4,4,CV_64F) ); } for(int currImage = 0; currImage < numImages; currImage++ ) { CV_CALL( matrsUk[currImage] = cvCreateMat(12,12,CV_64F) ); CV_CALL( workMatrsUk[currImage] = cvCreateMat(12,12,CV_64F) ); int currVisPoint = 0, currPoint, numVisPoint; for( currPoint = 0; currPoint < numPoints; currPoint++ ) { if( cvmGet(pointsPres[currImage],0,currPoint) > 0 ) { currVisPoint++; } } numVisPoint = currVisPoint; /* Allocate memory for current image data */ CV_CALL( observVisPoints[currImage] = cvCreateMat(2,numVisPoint,CV_64F) ); CV_CALL( projVisPoints[currImage] = cvCreateMat(2,numVisPoint,CV_64F) ); /* create error matrix */ CV_CALL( errorProjPoints[currImage] = cvCreateMat(2,numVisPoint,CV_64F) ); /* Create derivate matrices */ CV_CALL( DerivProj[currImage] = cvCreateMat(2*numVisPoint,12,CV_64F) ); CV_CALL( DerivPoint[currImage] = cvCreateMat(2,numVisPoint*4,CV_64F) ); /* Copy observed projected visible points */ currVisPoint = 0; for( currPoint = 0; currPoint < numPoints; currPoint++ ) { if( cvmGet(pointsPres[currImage],0,currPoint) > 0 ) { cvmSet(observVisPoints[currImage],0,currVisPoint,cvmGet(observProjPoints[currImage],0,currPoint)); cvmSet(observVisPoints[currImage],1,currVisPoint,cvmGet(observProjPoints[currImage],1,currPoint)); currVisPoint++; } } } /*---------------------------------------------------*/ CV_CALL( matrTmpSys1 = cvCreateMat(numPoints*4, numImages*12, CV_64F) ); CV_CALL( matrSysDeltaP = cvCreateMat(numImages*12, numImages*12, CV_64F) ); CV_CALL( vectTmpSys3 = cvCreateMat(numPoints*4,1,CV_64F) ); CV_CALL( vectSysDeltaP = cvCreateMat(numImages*12,1,CV_64F) ); CV_CALL( deltaP = cvCreateMat(numImages*12,1,CV_64F) ); CV_CALL( deltaM = cvCreateMat(numPoints*4,1,CV_64F) ); CV_CALL( vectTmpSysM = cvCreateMat(numPoints*4,1,CV_64F) ); //#ifdef TRACK_BUNDLE #if 1 { /* Create file to track */ FILE* file; file = fopen( TRACK_BUNDLE_FILE ,"w"); fprintf(file,"begin\n"); fclose(file); } #endif /* ============= main optimization loop ============== */ /* project all points using current vector X */ icvProjPointsStatusFunc(numImages, vectorX_points4D, vectorX_projMatrs, pointsPres, projVisPoints); /* Compute error with observed value and computed projection */ double prevError; prevError = 0; for(int currImage = 0; currImage < numImages; currImage++ ) { cvSub(observVisPoints[currImage],projVisPoints[currImage],errorProjPoints[currImage]); double currNorm = cvNorm(errorProjPoints[currImage]); prevError += currNorm * currNorm; } prevError = sqrt(prevError); int currIter; double change; double alpha; //#ifdef TRACK_BUNDLE #if 1 { /* Create file to track */ FILE* file; file = fopen( TRACK_BUNDLE_FILE ,"a"); fprintf(file,"\n========================================\n");; fprintf(file,"Iter=0\n"); fprintf(file,"Error = %20.15lf\n",prevError); fprintf(file,"Change = %20.15lf\n",1.0); fprintf(file,"projection errors\n"); /* Print all proejction errors */ for(int currImage = 0; currImage < numImages; currImage++) { fprintf(file,"\nImage=%d\n",currImage); int numPn = errorProjPoints[currImage]->cols; for( int currPoint = 0; currPoint < numPn; currPoint++ ) { double ex,ey; ex = cvmGet(errorProjPoints[currImage],0,currPoint); ey = cvmGet(errorProjPoints[currImage],1,currPoint); fprintf(file,"%40.35lf, %40.35lf\n",ex,ey); } } fclose(file); } #endif currIter = 0; change = 1; alpha = 0.001; do { #ifdef TRACK_BUNDLE { FILE *file; file = fopen( TRACK_BUNDLE_FILE ,"a"); fprintf(file,"\n----- test 6 do main -----\n"); double norm = cvNorm(vectorX_points4D); fprintf(file," test 6.01 prev normPnts=%lf\n",norm); for( int i=0;icols; for( int currPoint = 0; currPoint < numPn; currPoint++ ) { double ex,ey; ex = cvmGet(errorProjPoints[currImage],0,currPoint); ey = cvmGet(errorProjPoints[currImage],1,currPoint); fprintf(file,"%lf,%lf\n",ex,ey); } } fprintf(file,"\n---- test 0 -----\n"); #endif fclose(file); } #endif /* Compare new error and last error */ if( newError < prevError ) {/* accept new value */ prevError = newError; /* Compute relative change of required parameter vectorX. change = norm(curr-prev) / norm(curr) ) */ { double normAll1 = 0; double normAll2 = 0; double currNorm1 = 0; double currNorm2 = 0; /* compute norm for projection matrices */ for(int currImage = 0; currImage < numImages; currImage++ ) { currNorm1 = cvNorm(newVectorX_projMatrs[currImage],vectorX_projMatrs[currImage]); currNorm2 = cvNorm(newVectorX_projMatrs[currImage]); normAll1 += currNorm1 * currNorm1; normAll2 += currNorm2 * currNorm2; } /* compute norm for points */ currNorm1 = cvNorm(newVectorX_points4D,vectorX_points4D); currNorm2 = cvNorm(newVectorX_points4D); normAll1 += currNorm1 * currNorm1; normAll2 += currNorm2 * currNorm2; /* compute change */ change = sqrt(normAll1) / sqrt(normAll2); //#ifdef TRACK_BUNDLE #if 1 { /* Create file to track */ FILE* file; file = fopen( TRACK_BUNDLE_FILE ,"a"); fprintf(file,"\nChange inside newVal change = %20.15lf\n",change); fprintf(file," normAll1= %20.15lf\n",sqrt(normAll1)); fprintf(file," normAll2= %20.15lf\n",sqrt(normAll2)); fclose(file); } #endif } alpha /= 10; for(int currImage = 0; currImage < numImages; currImage++ ) { cvCopy(newVectorX_projMatrs[currImage],vectorX_projMatrs[currImage]); } cvCopy(newVectorX_points4D,vectorX_points4D); break; } else { alpha *= 10; } } while( change > epsilon && currIter < maxIter );/* solve normal equation using current alpha */ //#ifdef TRACK_BUNDLE #if 1 { FILE* file; file = fopen( TRACK_BUNDLE_FILE ,"a"); fprintf(file,"\nBest error = %40.35lf\n",prevError); fclose(file); } #endif } while( change > epsilon && currIter < maxIter ); /*--------------------------------------------*/ /* Optimization complete copy computed params */ /* Copy projection matrices */ for(int currImage = 0; currImage < numImages; currImage++ ) { cvCopy(newVectorX_projMatrs[currImage],resultProjMatrs[currImage]); } /* Copy 4D points */ cvCopy(newVectorX_points4D,resultPoints4D); // free(memory); __END__; /* Free allocated memory */ /* Free simple matrices */ cvFree(&vectorX_points4D); cvFree(&newVectorX_points4D); cvFree(&changeVectorX_points4D); cvFree(&changeVectorX_projMatrs); cvFree(&matrW); cvFree(&workMatrVi); cvFree(&jacProjErr); cvFree(&jacPointErr); cvFree(&matrTmpSys1); cvFree(&matrSysDeltaP); cvFree(&vectTmpSys3); cvFree(&vectSysDeltaP); cvFree(&deltaP); cvFree(&deltaM); cvFree(&vectTmpSysM); /* Free arrays of matrices */ icvFreeMatrixArray(&vectorX_projMatrs,numImages); icvFreeMatrixArray(&newVectorX_projMatrs,numImages); icvFreeMatrixArray(&observVisPoints,numImages); icvFreeMatrixArray(&projVisPoints,numImages); icvFreeMatrixArray(&errorProjPoints,numImages); icvFreeMatrixArray(&DerivProj,numImages); icvFreeMatrixArray(&DerivPoint,numImages); icvFreeMatrixArray(&matrsUk,numImages); icvFreeMatrixArray(&workMatrsUk,numImages); icvFreeMatrixArray(&matrsVi,numPoints); icvFreeMatrixArray(&workMatrsInvVi,numPoints); return; }