mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1782 lines
58 KiB
1782 lines
58 KiB
/*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 "cvtypes.h" |
|
#include <float.h> |
|
#include <limits.h> |
|
//#include "cv.h" |
|
|
|
#include <stdio.h> |
|
|
|
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;i<numImages;i++ ) |
|
{ |
|
double norm = cvNorm(vectorX_projMatrs[i]); |
|
fprintf(file," test 6.01 prev normProj=%lf\n",norm); |
|
} |
|
|
|
fclose(file); |
|
} |
|
#endif |
|
|
|
/* Compute derivates by projectinon matrices */ |
|
icvComputeDerivateProjAll(vectorX_points4D,vectorX_projMatrs,pointsPres,numImages,DerivProj); |
|
|
|
/* Compute derivates by 4D points */ |
|
icvComputeDerivatePointsAll(vectorX_points4D,vectorX_projMatrs,pointsPres,numImages,DerivPoint); |
|
|
|
/* Compute matrces Uk */ |
|
icvComputeMatrixUAll(numImages,DerivProj,matrsUk); |
|
icvComputeMatrixVAll(numImages,DerivPoint,pointsPres,matrsVi); |
|
icvComputeMatrixW(numImages,DerivProj,DerivPoint,pointsPres,matrW); |
|
|
|
|
|
#ifdef TRACK_BUNDLE |
|
{ |
|
FILE *file; |
|
file = fopen( TRACK_BUNDLE_FILE ,"a"); |
|
fprintf(file,"\n----- test 6.03 do matrs U V -----\n"); |
|
|
|
int i; |
|
for( i = 0; i < numImages; i++ ) |
|
{ |
|
double norm = cvNorm(matrsUk[i]); |
|
fprintf(file," test 6.01 prev matrsUk=%lf\n",norm); |
|
} |
|
|
|
for( i = 0; i < numPoints; i++ ) |
|
{ |
|
double norm = cvNorm(matrsVi[i]); |
|
fprintf(file," test 6.01 prev matrsVi=%lf\n",norm); |
|
} |
|
|
|
fclose(file); |
|
} |
|
#endif |
|
|
|
/* Compute jac errors */ |
|
icvComputeJacErrorProj(numImages, DerivProj, errorProjPoints, jacProjErr); |
|
icvComputeJacErrorPoint(numImages, DerivPoint, errorProjPoints, pointsPres, jacPointErr); |
|
|
|
#ifdef TRACK_BUNDLE |
|
{ |
|
FILE *file; |
|
file = fopen( TRACK_BUNDLE_FILE ,"a"); |
|
fprintf(file,"\n----- test 6 do main -----\n"); |
|
double norm1 = cvNorm(vectorX_points4D); |
|
fprintf(file," test 6.02 post normPnts=%lf\n",norm1); |
|
fclose(file); |
|
} |
|
#endif |
|
/* Copy matrices Uk to work matrices Uk */ |
|
for(int currImage = 0; currImage < numImages; currImage++ ) |
|
{ |
|
cvCopy(matrsUk[currImage],workMatrsUk[currImage]); |
|
} |
|
|
|
#ifdef TRACK_BUNDLE |
|
{ |
|
FILE *file; |
|
file = fopen( TRACK_BUNDLE_FILE ,"a"); |
|
fprintf(file,"\n----- test 60.3 do matrs U V -----\n"); |
|
|
|
int i; |
|
for( i = 0; i < numImages; i++ ) |
|
{ |
|
double norm = cvNorm(matrsUk[i]); |
|
fprintf(file," test 6.01 post1 matrsUk=%lf\n",norm); |
|
} |
|
|
|
for( i = 0; i < numPoints; i++ ) |
|
{ |
|
double norm = cvNorm(matrsVi[i]); |
|
fprintf(file," test 6.01 post1 matrsVi=%lf\n",norm); |
|
} |
|
|
|
fclose(file); |
|
} |
|
#endif |
|
|
|
/* ========== Solve normal equation for given alpha and Jacobian ============ */ |
|
|
|
do |
|
{ |
|
/* ---- Add alpha to matrices --- */ |
|
/* Add alpha to matrInvVi and make workMatrsInvVi */ |
|
|
|
int currV; |
|
for( currV = 0; currV < numPoints; currV++ ) |
|
{ |
|
cvCopy(matrsVi[currV],workMatrVi); |
|
|
|
for( i = 0; i < 4; i++ ) |
|
{ |
|
cvmSet(workMatrVi,i,i,cvmGet(matrsVi[currV],i,i)*(1+alpha) ); |
|
} |
|
|
|
cvInvert(workMatrVi,workMatrsInvVi[currV],CV_LU/*,&currV*/); |
|
} |
|
|
|
/* Add alpha to matrUk and make matrix workMatrsUk */ |
|
for(int currImage = 0; currImage< numImages; currImage++ ) |
|
{ |
|
|
|
for( i = 0; i < 12; i++ ) |
|
{ |
|
cvmSet(workMatrsUk[currImage],i,i,cvmGet(matrsUk[currImage],i,i)*(1+alpha)); |
|
} |
|
|
|
|
|
} |
|
|
|
/* Fill matrix to make system for computing delta P (matrTmpSys1 = inv(V)*tr(W) )*/ |
|
for( currV = 0; currV < numPoints; currV++ ) |
|
{ |
|
int currRowV; |
|
for( currRowV = 0; currRowV < 4; currRowV++ ) |
|
{ |
|
for(int currImage = 0; currImage < numImages; currImage++ ) |
|
{ |
|
for( int currCol = 0; currCol < 12; currCol++ )/* For each column of transposed matrix W */ |
|
{ |
|
double sum = 0; |
|
for( i = 0; i < 4; i++ ) |
|
{ |
|
sum += cvmGet(workMatrsInvVi[currV],currRowV,i) * |
|
cvmGet(matrW,currImage*12+currCol,currV*4+i); |
|
} |
|
cvmSet(matrTmpSys1,currV*4+currRowV,currImage*12+currCol,sum); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
/* Fill matrix to make system for computing delta P (matrTmpSys2 = W * matrTmpSys ) */ |
|
cvmMul(matrW,matrTmpSys1,matrSysDeltaP); |
|
|
|
/* need to compute U-matrTmpSys2. But we compute matTmpSys2-U */ |
|
for(int currImage = 0; currImage < numImages; currImage++ ) |
|
{ |
|
CvMat subMatr; |
|
cvGetSubRect(matrSysDeltaP,&subMatr,cvRect(currImage*12,currImage*12,12,12)); |
|
cvSub(&subMatr,workMatrsUk[currImage],&subMatr); |
|
} |
|
|
|
/* Compute right side of normal equation */ |
|
for( currV = 0; currV < numPoints; currV++ ) |
|
{ |
|
CvMat subMatrErPnts; |
|
CvMat subMatr; |
|
cvGetSubRect(jacPointErr,&subMatrErPnts,cvRect(0,currV*4,1,4)); |
|
cvGetSubRect(vectTmpSys3,&subMatr,cvRect(0,currV*4,1,4)); |
|
cvmMul(workMatrsInvVi[currV],&subMatrErPnts,&subMatr); |
|
} |
|
|
|
cvmMul(matrW,vectTmpSys3,vectSysDeltaP); |
|
cvSub(vectSysDeltaP,jacProjErr,vectSysDeltaP); |
|
|
|
/* Now we can compute part of normal system - deltaP */ |
|
cvSolve(matrSysDeltaP ,vectSysDeltaP, deltaP, CV_SVD); |
|
|
|
/* Print deltaP to file */ |
|
|
|
#ifdef TRACK_BUNDLE |
|
{ |
|
FILE* file; |
|
file = fopen( TRACK_BUNDLE_FILE_DELTAP ,"w"); |
|
|
|
for(int currImage = 0; currImage < numImages; currImage++ ) |
|
{ |
|
fprintf(file,"\nImage=%d\n",currImage); |
|
int i; |
|
for( i = 0; i < 12; i++ ) |
|
{ |
|
double val; |
|
val = cvmGet(deltaP,currImage*12+i,0); |
|
fprintf(file,"%lf\n",val); |
|
} |
|
fprintf(file,"\n"); |
|
} |
|
fclose(file); |
|
} |
|
#endif |
|
/* We know deltaP and now we can compute system for deltaM */ |
|
for( i = 0; i < numPoints * 4; i++ ) |
|
{ |
|
double sum = 0; |
|
for( int j = 0; j < numImages * 12; j++ ) |
|
{ |
|
sum += cvmGet(matrW,j,i) * cvmGet(deltaP,j,0); |
|
} |
|
cvmSet(vectTmpSysM,i,0,cvmGet(jacPointErr,i,0)-sum); |
|
} |
|
|
|
/* Compute deltaM */ |
|
for( currV = 0; currV < numPoints; currV++ ) |
|
{ |
|
CvMat subMatr; |
|
CvMat subMatrM; |
|
cvGetSubRect(vectTmpSysM,&subMatr,cvRect(0,currV*4,1,4)); |
|
cvGetSubRect(deltaM,&subMatrM,cvRect(0,currV*4,1,4)); |
|
cvmMul(workMatrsInvVi[currV],&subMatr,&subMatrM); |
|
} |
|
|
|
/* We know delta and compute new value of vector X: nextVectX = vectX + deltas */ |
|
|
|
/* Compute new P */ |
|
for(int currImage = 0; currImage < numImages; currImage++ ) |
|
{ |
|
for( i = 0; i < 3; i++ ) |
|
{ |
|
for( int j = 0; j < 4; j++ ) |
|
{ |
|
cvmSet(newVectorX_projMatrs[currImage],i,j, |
|
cvmGet(vectorX_projMatrs[currImage],i,j) + cvmGet(deltaP,currImage*12+i*4+j,0)); |
|
} |
|
} |
|
} |
|
|
|
/* Compute new M */ |
|
int currPoint; |
|
for( currPoint = 0; currPoint < numPoints; currPoint++ ) |
|
{ |
|
for( i = 0; i < 4; i++ ) |
|
{ |
|
cvmSet(newVectorX_points4D,i,currPoint, |
|
cvmGet(vectorX_points4D,i,currPoint) + cvmGet(deltaM,currPoint*4+i,0)); |
|
} |
|
} |
|
|
|
/* ----- Compute errors for new vectorX ----- */ |
|
/* Project points using new vectorX and status of each point */ |
|
icvProjPointsStatusFunc(numImages, newVectorX_points4D, newVectorX_projMatrs, pointsPres, projVisPoints); |
|
/* Compute error with observed value and computed projection */ |
|
double newError = 0; |
|
for(int currImage = 0; currImage < numImages; currImage++ ) |
|
{ |
|
cvSub(observVisPoints[currImage],projVisPoints[currImage],errorProjPoints[currImage]); |
|
double currNorm = cvNorm(errorProjPoints[currImage]); |
|
|
|
//#ifdef TRACK_BUNDLE |
|
#if 1 |
|
{ |
|
FILE *file; |
|
file = fopen( TRACK_BUNDLE_FILE ,"a"); |
|
fprintf(file,"\n----- test 13,01 currImage=%d currNorm=%lf -----\n",currImage,currNorm); |
|
fclose(file); |
|
} |
|
#endif |
|
newError += currNorm * currNorm; |
|
} |
|
newError = sqrt(newError); |
|
|
|
currIter++; |
|
|
|
|
|
|
|
|
|
//#ifdef TRACK_BUNDLE |
|
#if 1 |
|
{ |
|
/* Create file to track */ |
|
FILE* file; |
|
file = fopen( TRACK_BUNDLE_FILE ,"a"); |
|
fprintf(file,"\n========================================\n"); |
|
fprintf(file,"numPoints=%d\n",numPoints); |
|
fprintf(file,"Iter=%d\n",currIter); |
|
fprintf(file,"Error = %20.15lf\n",newError); |
|
fprintf(file,"Change = %20.15lf\n",change); |
|
|
|
|
|
/* Print all projection errors */ |
|
#if 0 |
|
fprintf(file,"projection errors\n"); |
|
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,"%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; |
|
}
|
|
|