00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <new>
00043
00044 #include "LinearAlgebraCV.h"
00045 #include "LinearAlgebra.h"
00046 #include "Math/FloatMatrix.h"
00047 #include "Math/FloatVector.h"
00048 #include "Math/DoubleMatrix.h"
00049 #include "Math/DoubleVector.h"
00050 #include "Math/Math2d.h"
00051 #include "Math/Math3d.h"
00052 #include "Helpers/helpers.h"
00053
00054 #include <float.h>
00055 #include <math.h>
00056 #include <stdio.h>
00057
00058
00059
00060
00061
00062
00063
00064 void LinearAlgebraCV::SolveLinearLeastSquaresHomogeneousSVD(const CFloatMatrix *A, CFloatVector *x)
00065 {
00066 if (A->columns != x->dimension)
00067 {
00068 printf("error: A, b, x do not match LinearAlgebraCV::SolveLinearLeastSquaresHomogeneousSVD");
00069 return;
00070 }
00071
00072 if (A->rows < A->columns)
00073 {
00074 printf("error: equation system is underdetermined in LinearAlgebraCV::SolveLinearLeastSquaresHomogeneousSVD\n");
00075 return;
00076 }
00077
00078 const int m = A->rows;
00079 const int n = A->columns;
00080
00081 CFloatMatrix W(n, m), V(n, n);
00082
00083 SVD(A, &W, 0, &V, false, false, false);
00084
00085 for (int i = 0, offset = n - 1; i < n; i++, offset += n)
00086 x->data[i] = V.data[offset];
00087 }
00088
00089 void LinearAlgebraCV::SolveLinearLeastSquaresSVD(const CFloatMatrix *A, const CFloatVector *b, CFloatVector *x)
00090 {
00091 if (A->columns != x->dimension || A->rows != b->dimension)
00092 {
00093 printf("error: A, b, x do not match LinearAlgebraCV::SolveLinearLeastSquaresSVD");
00094 return;
00095 }
00096
00097 if (A->rows < A->columns)
00098 {
00099 printf("error: equation system is underdetermined in LinearAlgebraCV::SolveLinearLeastSquaresSVD\n");
00100 return;
00101 }
00102
00103 CFloatMatrix A_(A->rows, A->columns);
00104 CalculatePseudoInverseSVD(A, &A_);
00105 LinearAlgebra::MulMatVec(&A_, b, x);
00106 }
00107
00108 void LinearAlgebraCV::SolveLinearLeastSquaresSimple(const CFloatMatrix *A, const CFloatVector *b, CFloatVector *x)
00109 {
00110 if (A->columns != x->dimension || A->rows != b->dimension)
00111 {
00112 printf("error: A, b, x do not match LinearAlgebraCV::SolveLinearLeastSquaresSimple");
00113 return;
00114 }
00115
00116 if (A->rows < A->columns)
00117 {
00118 printf("error: equation system is underdetermined in LinearAlgebraCV::SolveLinearLeastSquaresSimple\n");
00119 return;
00120 }
00121
00122 CFloatMatrix A_(A->rows, A->columns);
00123 CalculatePseudoInverseSimple(A, &A_);
00124 LinearAlgebra::MulMatVec(&A_, b, x);
00125 }
00126
00127 void LinearAlgebraCV::CalculatePseudoInverseSVD(const CFloatMatrix *pInputMatrix, CFloatMatrix *pResultMatrix)
00128 {
00129 if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
00130 {
00131 printf("error: input and output matrix do not match LinearAlgebraCV::CalculatePseudoInverseSVD");
00132 return;
00133 }
00134
00135
00136
00137
00138
00139
00140 const CFloatMatrix *A = pInputMatrix;
00141 const int m = pInputMatrix->rows;
00142 const int n = pInputMatrix->columns;
00143
00144 CFloatMatrix W(n, m), WT(m, n), UT(m, m), V(n, n);
00145
00146
00147 SVD(A, &W, &UT, &V, false, true, false);
00148
00149
00150 Transpose(&W, &WT);
00151
00152 const int min = MY_MIN(m, n);
00153
00154 int i;
00155 float fThreshold = 0.0f;
00156
00157 for (i = 0; i < min; i++)
00158 fThreshold += WT(i, i);
00159
00160 fThreshold *= 2 * FLT_EPSILON;
00161
00162
00163 for (i = 0; i < min; i++)
00164 if (WT(i, i) < fThreshold)
00165 WT(i, i) = 0.0f;
00166 else
00167 WT(i, i) = 1.0f / WT(i, i);
00168
00169
00170 CFloatMatrix temp(m, n);
00171 Multiply(&V, &WT, &temp);
00172 Multiply(&temp, &UT, pResultMatrix);
00173 }
00174
00175 void LinearAlgebraCV::CalculatePseudoInverseSimple(const CFloatMatrix *pInputMatrix, CFloatMatrix *pResultMatrix)
00176 {
00177 if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
00178 {
00179 printf("error: input and output matrix do not match LinearAlgebraCV::CalculatePseudoInverseSimple");
00180 return;
00181 }
00182
00183
00184
00185
00186 const CFloatMatrix *A = pInputMatrix;
00187 const int m = pInputMatrix->rows;
00188 const int n = pInputMatrix->columns;
00189
00190 CFloatMatrix AT(m, n), ATA(n, n), ATA_inverted(n, n);
00191
00192 Transpose(A, &AT);
00193 Multiply(&AT, A, &ATA);
00194 Invert(&ATA, &ATA_inverted);
00195 Multiply(&ATA_inverted, &AT, pResultMatrix);
00196 }
00197
00198 void LinearAlgebraCV::Invert(const CFloatMatrix *pInputMatrix, const CFloatMatrix *pResultMatrix)
00199 {
00200 if (pInputMatrix->columns != pInputMatrix->rows)
00201 {
00202 printf("error: input is not square matrix in LinearAlgebraCV::Invert");
00203 return;
00204 }
00205
00206 if (pInputMatrix->columns != pResultMatrix->columns || pInputMatrix->rows != pResultMatrix->rows)
00207 {
00208 printf("error: input and output matrix are not the same in LinearAlgebraCV::Invert");
00209 return;
00210 }
00211
00212 CvMat inputMatrix = cvMat(pInputMatrix->rows, pInputMatrix->columns, CV_32FC1, pInputMatrix->data);
00213 CvMat resultMatrix = cvMat(pResultMatrix->rows, pResultMatrix->columns, CV_32FC1, pResultMatrix->data);
00214
00215 cvInvert(&inputMatrix, &resultMatrix);
00216 }
00217
00218 void LinearAlgebraCV::Transpose(const CFloatMatrix *pInputMatrix, const CFloatMatrix *pResultMatrix)
00219 {
00220 if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
00221 {
00222 printf("error: input and output matrix do not match LinearAlgebraCV::Transpose");
00223 return;
00224 }
00225
00226 CvMat inputMatrix = cvMat(pInputMatrix->rows, pInputMatrix->columns, CV_32FC1, pInputMatrix->data);
00227 CvMat resultMatrix = cvMat(pResultMatrix->rows, pResultMatrix->columns, CV_32FC1, pResultMatrix->data);
00228
00229 cvTranspose(&inputMatrix, &resultMatrix);
00230 }
00231
00232 void LinearAlgebraCV::CalculateCovarianceMatrix(const CFloatMatrix *pMatrix, CFloatMatrix *pCovarianceMatrix)
00233 {
00234 if (pCovarianceMatrix->columns != pMatrix->columns || pCovarianceMatrix->rows != pMatrix->columns)
00235 return;
00236
00237 const int columns = pMatrix->columns;
00238 const int rows = pMatrix->rows;
00239
00240 CvMat covarianceMatrix = cvMat(columns, columns, CV_32FC1, pCovarianceMatrix->data);
00241
00242 CvMat **ppInput = new CvMat*[rows];
00243 for (int i = 0; i < rows; i++)
00244 {
00245 CvMat *vector = cvCreateMatHeader(1, columns, CV_32FC1);
00246 cvInitMatHeader(vector, 1, columns, CV_32FC1, pMatrix->data + i * columns);
00247 ppInput[i] = vector;
00248 }
00249
00250 CvMat *avg = cvCreateMat(1, columns, CV_32FC1);
00251
00252 #ifdef CV_COVAR_NORMAL
00253 cvCalcCovarMatrix((const CvArr **) ppInput, rows, &covarianceMatrix, avg, CV_COVAR_NORMAL);
00254 #else
00255 cvCalcCovarMatrix((const CvArr **) ppInput, &covarianceMatrix, avg);
00256 #endif
00257
00258 cvReleaseMat(&avg);
00259 }
00260
00261 void LinearAlgebraCV::Multiply(const CFloatMatrix *A, const CFloatMatrix *B, CFloatMatrix *pResultMatrix, bool bTransposeB)
00262 {
00263 if (!bTransposeB && (A->columns != B->rows || pResultMatrix->columns != B->columns || pResultMatrix->rows != A->rows))
00264 {
00265 printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebraCV::Multiply\n");
00266 return;
00267 }
00268
00269 if (bTransposeB && (A->columns != B->columns || pResultMatrix->columns != B->rows || pResultMatrix->rows != A->rows))
00270 {
00271 printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebraCV::Multiply\n");
00272 return;
00273 }
00274
00275 int flags = 0;
00276
00277 if (bTransposeB)
00278 flags = CV_GEMM_B_T;
00279
00280 CvMat matrixA = cvMat(A->rows, A->columns, CV_32FC1, A->data);
00281 CvMat matrixB = cvMat(B->rows, B->columns, CV_32FC1, B->data);
00282 CvMat result_matrix = cvMat(pResultMatrix->rows, pResultMatrix->columns, CV_32FC1, pResultMatrix->data);
00283
00284 cvGEMM(&matrixA, &matrixB, 1, 0, 1, &result_matrix, flags);
00285 }
00286
00287 void LinearAlgebraCV::SelfProduct(const CFloatMatrix *pMatrix, CFloatMatrix *pResultMatrix, bool bTransposeSecond)
00288 {
00289 if (pResultMatrix->columns != pMatrix->columns || pResultMatrix->rows != pMatrix->columns)
00290 return;
00291
00292 CvMat matrix = cvMat(pMatrix->rows, pMatrix->columns, CV_32FC1, pMatrix->data);
00293 CvMat result_matrix = cvMat(pResultMatrix->rows, pResultMatrix->columns, CV_32FC1, pResultMatrix->data);
00294
00295 if (bTransposeSecond)
00296 cvGEMM(&matrix, &matrix, 1, 0, 1, &result_matrix, CV_GEMM_B_T);
00297 else
00298 cvGEMM(&matrix, &matrix, 1, 0, 1, &result_matrix, CV_GEMM_A_T);
00299 }
00300
00301 void LinearAlgebraCV::SVD(const CFloatMatrix *A, CFloatMatrix *W, CFloatMatrix *U, CFloatMatrix *V, bool bAllowModifyA, bool bReturnUTransposed, bool bReturnVTransposed)
00302 {
00303 const int columns = A->columns;
00304 const int rows = A->rows;
00305
00306 if (W->columns != columns || W->rows != rows)
00307 {
00308 printf("error: W should have %i columns and %i rows for LinearAlgebra::SVD\n", columns, rows);
00309 return;
00310 }
00311
00312 if (U && (U->columns != rows || U->rows != rows))
00313 {
00314 printf("error: U should have %i columns and %i rows for LinearAlgebra::SVD\n", rows, rows);
00315 return;
00316 }
00317
00318 if (V && (V->columns != columns || V->rows != columns))
00319 {
00320 printf("error: V should have %i columns and %i rows for LinearAlgebra::SVD\n", columns, columns);
00321 return;
00322 }
00323
00324 int flags = 0;
00325
00326 if (bAllowModifyA)
00327 flags |= CV_SVD_MODIFY_A;
00328
00329 if (bReturnUTransposed)
00330 flags |= CV_SVD_U_T;
00331
00332 if (bReturnVTransposed)
00333 flags |= CV_SVD_V_T;
00334
00335 CvMat matrixA = cvMat(rows, columns, CV_32FC1, A->data);
00336 CvMat matrixW = cvMat(rows, columns, CV_32FC1, W->data);
00337
00338 if (U && V)
00339 {
00340 CvMat matrixU = cvMat(rows, rows, CV_32FC1, U->data);
00341 CvMat matrixV = cvMat(columns, columns, CV_32FC1, V->data);
00342
00343 cvSVD(&matrixA, &matrixW, &matrixU, &matrixV, flags);
00344 }
00345 else if (U)
00346 {
00347 CvMat matrixU = cvMat(rows, rows, CV_32FC1, U->data);
00348
00349 cvSVD(&matrixA, &matrixW, &matrixU, 0, flags);
00350 }
00351 else if (V)
00352 {
00353 CvMat matrixV = cvMat(columns, columns, CV_32FC1, V->data);
00354
00355 cvSVD(&matrixA, &matrixW, 0, &matrixV, flags);
00356 }
00357 else
00358 {
00359 cvSVD(&matrixA, &matrixW, 0, 0, flags);
00360 }
00361 }
00362
00363 void LinearAlgebraCV::PCA(const CFloatMatrix *pData, CFloatMatrix *pTransformationMatrix, CFloatMatrix *pTransformedData, int nTargetDimension)
00364 {
00365 if (nTargetDimension > pData->columns)
00366 {
00367 printf("error: target dimension is greater than number of columns in training data matrix in LinearAlgebraCV::PCA\n");
00368 return;
00369 }
00370
00371 const int samples = pData->rows;
00372 const int dimension = pData->columns;
00373
00374 if (pTransformationMatrix->columns != dimension || pTransformationMatrix->rows != nTargetDimension ||
00375 pTransformedData->columns != samples || pTransformedData->rows != nTargetDimension)
00376 {
00377 printf("error: input to LinearAlgebraCV::PCA does not match\n");
00378 return;
00379 }
00380
00381 CFloatMatrix adjustedData(pData);
00382 CFloatMatrix covarianceMatrix(dimension, dimension);
00383 CFloatMatrix eigenValues(dimension, dimension);
00384 CFloatMatrix eigenVectors(dimension, dimension);
00385
00386 printf("subtracting mean from columns...\n");
00387 LinearAlgebra::SubtractMeanFromColumns(pData, &adjustedData);
00388
00389 printf("calculating covariance matrix...\n");
00390 LinearAlgebraCV::SelfProduct(&adjustedData, &covarianceMatrix);
00391
00392 printf("calculating SVD on %ix%i matrix...\n", dimension, dimension);
00393 LinearAlgebraCV::SVD(&covarianceMatrix, &eigenValues, &eigenVectors, 0, true, true);
00394
00395 printf("SVD calculated\n");
00396
00397 for (int i = 0, offset = 0; i < nTargetDimension; i++)
00398 {
00399 for (int j = 0; j < dimension; j++)
00400 {
00401 pTransformationMatrix->data[offset] = eigenVectors.data[i * dimension + j];
00402 offset++;
00403 }
00404 }
00405
00406 LinearAlgebraCV::Multiply(pTransformationMatrix, pData, pTransformedData, true);
00407 }
00408
00409 void LinearAlgebraCV::PCA(const CFloatMatrix *pData, CFloatMatrix *pTransformationMatrix, CFloatMatrix *pEigenValues)
00410 {
00411 const int samples = pData->rows;
00412 const int dimension = pData->columns;
00413
00414 if (pTransformationMatrix->columns != dimension || pTransformationMatrix->rows != dimension || pEigenValues->columns != 1 || pEigenValues->rows != dimension)
00415 return;
00416
00417 CFloatMatrix adjustedData(pData);
00418 CFloatMatrix covarianceMatrix(dimension, dimension);
00419 CFloatMatrix eigenValues(dimension, dimension);
00420 CFloatMatrix eigenVectors(dimension, dimension);
00421
00422 printf("subtracting mean from columns...\n");
00423 LinearAlgebra::SubtractMeanFromColumns(pData, &adjustedData);
00424
00425 printf("calculating covariance matrix...\n");
00426 LinearAlgebraCV::SelfProduct(&adjustedData, &covarianceMatrix);
00427
00428 printf("calculating SVD on %ix%i matrix...\n", dimension, dimension);
00429 LinearAlgebraCV::SVD(&covarianceMatrix, &eigenValues, pTransformationMatrix, 0, true, true);
00430
00431 printf("SVD calculated\n");
00432
00433 for (int i = 0; i < dimension; i++)
00434 pEigenValues->data[i] = eigenValues.data[i * dimension + i];
00435 }
00436
00437 bool LinearAlgebraCV::DetermineAffineTransformation(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD)
00438 {
00439 if (nPoints < 3)
00440 {
00441 printf("error: not enough input point pairs for LinearAlgebraCV::DetermineAffineTransformation (must be at least 3)\n");
00442 return false;
00443 }
00444
00445 CFloatMatrix M(6, 2 * nPoints);
00446 CFloatVector b(2 * nPoints);
00447
00448 float *data = M.data;
00449
00450 for (int i = 0, offset = 0; i < nPoints; i++, offset += 12)
00451 {
00452 data[offset] = pSourcePoints[i].x;
00453 data[offset + 1] = pSourcePoints[i].y;
00454 data[offset + 2] = 1;
00455 data[offset + 3] = 0;
00456 data[offset + 4] = 0;
00457 data[offset + 5] = 0;
00458
00459 data[offset + 6] = 0;
00460 data[offset + 7] = 0;
00461 data[offset + 8] = 0;
00462 data[offset + 9] = pSourcePoints[i].x;
00463 data[offset + 10] = pSourcePoints[i].y;
00464 data[offset + 11] = 1;
00465
00466 const int index = 2 * i;
00467 b.data[index] = pTargetPoints[i].x;
00468 b.data[index + 1] = pTargetPoints[i].y;
00469 }
00470
00471 CFloatVector x(6);
00472
00473 if (bUseSVD)
00474 LinearAlgebraCV::SolveLinearLeastSquaresSVD(&M, &b, &x);
00475 else
00476 LinearAlgebraCV::SolveLinearLeastSquaresSimple(&M, &b, &x);
00477
00478 Math3d::SetMat(A, x.data[0], x.data[1], x.data[2], x.data[3], x.data[4], x.data[5], 0, 0, 1);
00479
00480 return true;
00481 }
00482
00483 bool LinearAlgebraCV::DetermineHomography(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD)
00484 {
00485 if (nPoints < 4)
00486 {
00487 printf("error: not enough input point pairs for LinearAlgebraCV::DetermineHomography (must be at least 4)\n");
00488 return false;
00489 }
00490
00491
00492
00493 CDoubleMatrix M(8, 2 * nPoints);
00494 CDoubleVector b(2 * nPoints);
00495
00496 double *data = M.data;
00497
00498 for (int i = 0, offset = 0; i < nPoints; i++, offset += 16)
00499 {
00500 data[offset] = pSourcePoints[i].x;
00501 data[offset + 1] = pSourcePoints[i].y;
00502 data[offset + 2] = 1;
00503 data[offset + 3] = 0;
00504 data[offset + 4] = 0;
00505 data[offset + 5] = 0;
00506 data[offset + 6] = -pSourcePoints[i].x * pTargetPoints[i].x;
00507 data[offset + 7] = -pSourcePoints[i].y * pTargetPoints[i].x;
00508
00509 data[offset + 8] = 0;
00510 data[offset + 9] = 0;
00511 data[offset + 10] = 0;
00512 data[offset + 11] = pSourcePoints[i].x;
00513 data[offset + 12] = pSourcePoints[i].y;
00514 data[offset + 13] = 1;
00515 data[offset + 14] = -pSourcePoints[i].x * pTargetPoints[i].y;
00516 data[offset + 15] = -pSourcePoints[i].y * pTargetPoints[i].y;
00517
00518 const int index = 2 * i;
00519 b.data[index] = pTargetPoints[i].x;
00520 b.data[index + 1] = pTargetPoints[i].y;
00521 }
00522
00523 CDoubleVector x(8);
00524
00525 if (bUseSVD)
00526 LinearAlgebraCV::SolveLinearLeastSquaresSVD(&M, &b, &x);
00527 else
00528 LinearAlgebraCV::SolveLinearLeastSquaresSimple(&M, &b, &x);
00529
00530 Math3d::SetMat(A, float(x.data[0]), float(x.data[1]), float(x.data[2]), float(x.data[3]), float(x.data[4]), float(x.data[5]), float(x.data[6]), float(x.data[7]), 1);
00531
00532 return true;
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542 void LinearAlgebraCV::SolveLinearLeastSquaresHomogeneousSVD(const CDoubleMatrix *A, CDoubleVector *x)
00543 {
00544 if (A->columns != x->dimension)
00545 {
00546 printf("error: A, b, x do not match LinearAlgebraCV::SolveLinearLeastSquaresHomogeneousSVD");
00547 return;
00548 }
00549
00550 if (A->rows < A->columns)
00551 {
00552 printf("error: equation system is underdetermined in LinearAlgebraCV::SolveLinearLeastSquaresHomogeneousSVD\n");
00553 return;
00554 }
00555
00556 const int m = A->rows;
00557 const int n = A->columns;
00558
00559 CDoubleMatrix W(n, m), V(n, n);
00560
00561 SVD(A, &W, 0, &V, false, false, false);
00562
00563 for (int i = 0, offset = n - 1; i < n; i++, offset += n)
00564 x->data[i] = V.data[offset];
00565 }
00566
00567 void LinearAlgebraCV::SolveLinearLeastSquaresSVD(const CDoubleMatrix *A, const CDoubleVector *b, CDoubleVector *x)
00568 {
00569 if (A->columns != x->dimension || A->rows != b->dimension)
00570 {
00571 printf("error: A, b, x do not match LinearAlgebraCV::SolveLinearLeastSquaresSVD");
00572 return;
00573 }
00574
00575 if (A->rows < A->columns)
00576 {
00577 printf("error: equation system is underdetermined in LinearAlgebraCV::SolveLinearLeastSquaresSVD\n");
00578 return;
00579 }
00580
00581 #if 0
00582 CvMat *AA = cvCreateMat(A->rows, A->columns, CV_64FC1);
00583 CvMat *BB = cvCreateMat(b->dimension, 1, CV_64FC1);
00584 CvMat *XX = cvCreateMat(x->dimension, 1, CV_64FC1);
00585
00586 int i;
00587
00588 for (i = 0; i < A->rows * A->columns; i++)
00589 AA->data.db[i] = A->data[i];
00590
00591 for (i = 0; i < b->dimension; i++)
00592 BB->data.db[i] = b->data[i];
00593
00594 cvSolve(AA, BB, XX, CV_SVD);
00595
00596 for (int k = 0; k < 8; k++)
00597 x->data[k] = XX->data.db[k];
00598
00599 cvReleaseMat(&AA);
00600 cvReleaseMat(&BB);
00601 cvReleaseMat(&XX);
00602 #else
00603 CDoubleMatrix A_(A->rows, A->columns);
00604 CalculatePseudoInverseSVD(A, &A_);
00605 LinearAlgebra::MulMatVec(&A_, b, x);
00606 #endif
00607 }
00608
00609 void LinearAlgebraCV::SolveLinearLeastSquaresSimple(const CDoubleMatrix *A, const CDoubleVector *b, CDoubleVector *x)
00610 {
00611 if (A->columns != x->dimension || A->rows != b->dimension)
00612 {
00613 printf("error: A, b, x do not match LinearAlgebraCV::SolveLinearLeastSquaresSimple");
00614 return;
00615 }
00616
00617 if (A->rows < A->columns)
00618 {
00619 printf("error: equation system is underdetermined in LinearAlgebraCV::SolveLinearLeastSquaresSimple\n");
00620 return;
00621 }
00622
00623 CDoubleMatrix A_(A->rows, A->columns);
00624 CalculatePseudoInverseSimple(A, &A_);
00625 LinearAlgebra::MulMatVec(&A_, b, x);
00626 }
00627
00628 void LinearAlgebraCV::CalculatePseudoInverseSVD(const CDoubleMatrix *pInputMatrix, CDoubleMatrix *pResultMatrix)
00629 {
00630 if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
00631 {
00632 printf("error: input and output matrix do not match LinearAlgebraCV::CalculatePseudoInverseSVD");
00633 return;
00634 }
00635
00636
00637
00638
00639
00640
00641 const CDoubleMatrix *A = pInputMatrix;
00642 const int m = pInputMatrix->rows;
00643 const int n = pInputMatrix->columns;
00644
00645 CDoubleMatrix W(n, m), WT(m, n), UT(m, m), V(n, n);
00646
00647
00648 SVD(A, &W, &UT, &V, false, true, false);
00649
00650
00651 Transpose(&W, &WT);
00652
00653 const int min = MY_MIN(m, n);
00654
00655 int i;
00656 double dThreshold = 0.0;
00657
00658 for(i = 0; i < min; i++)
00659 dThreshold += WT(i, i);
00660
00661 dThreshold *= 2 * DBL_EPSILON;
00662
00663
00664 for (i = 0; i < min; i++)
00665 if (WT(i, i) < dThreshold)
00666 WT(i, i) = 0;
00667 else
00668 WT(i, i) = 1.0 / WT(i, i);
00669
00670
00671 CDoubleMatrix temp(m, n);
00672 Multiply(&V, &WT, &temp);
00673 Multiply(&temp, &UT, pResultMatrix);
00674 }
00675
00676 void LinearAlgebraCV::CalculatePseudoInverseSimple(const CDoubleMatrix *pInputMatrix, CDoubleMatrix *pResultMatrix)
00677 {
00678 if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
00679 {
00680 printf("error: input and output matrix do not match LinearAlgebraCV::CalculatePseudoInverseSimple");
00681 return;
00682 }
00683
00684
00685
00686
00687 const CDoubleMatrix *A = pInputMatrix;
00688 const int m = pInputMatrix->rows;
00689 const int n = pInputMatrix->columns;
00690
00691 CDoubleMatrix AT(m, n), ATA(n, n), ATA_inverted(n, n);
00692
00693 Transpose(A, &AT);
00694 Multiply(&AT, A, &ATA);
00695 Invert(&ATA, &ATA_inverted);
00696 Multiply(&ATA_inverted, &AT, pResultMatrix);
00697 }
00698
00699 void LinearAlgebraCV::Invert(const CDoubleMatrix *pInputMatrix, const CDoubleMatrix *pResultMatrix)
00700 {
00701 if (pInputMatrix->columns != pInputMatrix->rows)
00702 {
00703 printf("error: input is not square matrix in LinearAlgebraCV::Invert");
00704 return;
00705 }
00706
00707 if (pInputMatrix->columns != pResultMatrix->columns || pInputMatrix->rows != pResultMatrix->rows)
00708 {
00709 printf("error: input and output matrix are not the same in LinearAlgebraCV::Invert");
00710 return;
00711 }
00712
00713 CvMat inputMatrix = cvMat(pInputMatrix->rows, pInputMatrix->columns, CV_64FC1, pInputMatrix->data);
00714 CvMat resultMatrix = cvMat(pResultMatrix->rows, pResultMatrix->columns, CV_64FC1, pResultMatrix->data);
00715
00716 cvInvert(&inputMatrix, &resultMatrix);
00717 }
00718
00719 void LinearAlgebraCV::Transpose(const CDoubleMatrix *pInputMatrix, const CDoubleMatrix *pResultMatrix)
00720 {
00721 if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
00722 {
00723 printf("error: input and output matrix do not match LinearAlgebraCV::Transpose");
00724 return;
00725 }
00726
00727 CvMat inputMatrix = cvMat(pInputMatrix->rows, pInputMatrix->columns, CV_64FC1, pInputMatrix->data);
00728 CvMat resultMatrix = cvMat(pResultMatrix->rows, pResultMatrix->columns, CV_64FC1, pResultMatrix->data);
00729
00730 cvTranspose(&inputMatrix, &resultMatrix);
00731 }
00732
00733 void LinearAlgebraCV::Multiply(const CDoubleMatrix *A, const CDoubleMatrix *B, CDoubleMatrix *pResultMatrix, bool bTransposeB)
00734 {
00735 if (!bTransposeB && (A->columns != B->rows || pResultMatrix->columns != B->columns || pResultMatrix->rows != A->rows))
00736 {
00737 printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebraCV::Multiply\n");
00738 return;
00739 }
00740
00741 if (bTransposeB && (A->columns != B->columns || pResultMatrix->columns != B->rows || pResultMatrix->rows != A->rows))
00742 {
00743 printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebraCV::Multiply\n");
00744 return;
00745 }
00746
00747 int flags = 0;
00748
00749 if (bTransposeB)
00750 flags = CV_GEMM_B_T;
00751
00752 CvMat matrixA = cvMat(A->rows, A->columns, CV_64FC1, A->data);
00753 CvMat matrixB = cvMat(B->rows, B->columns, CV_64FC1, B->data);
00754 CvMat result_matrix = cvMat(pResultMatrix->rows, pResultMatrix->columns, CV_64FC1, pResultMatrix->data);
00755
00756 cvGEMM(&matrixA, &matrixB, 1, 0, 1, &result_matrix, flags);
00757 }
00758
00759 void LinearAlgebraCV::SVD(const CDoubleMatrix *A, CDoubleMatrix *W, CDoubleMatrix *U, CDoubleMatrix *V, bool bAllowModifyA, bool bReturnUTransposed, bool bReturnVTransposed)
00760 {
00761 const int columns = A->columns;
00762 const int rows = A->rows;
00763
00764 if (W->columns != columns || W->rows != rows)
00765 {
00766 printf("error: W should have %i columns and %i rows for LinearAlgebra::SVD\n", columns, rows);
00767 return;
00768 }
00769
00770 if (U && (U->columns != rows || U->rows != rows))
00771 {
00772 printf("error: U should have %i columns and %i rows for LinearAlgebra::SVD\n", rows, rows);
00773 return;
00774 }
00775
00776 if (V && (V->columns != columns || V->rows != columns))
00777 {
00778 printf("error: V should have %i columns and %i rows for LinearAlgebra::SVD\n", columns, columns);
00779 return;
00780 }
00781
00782 int flags = 0;
00783
00784 if (bAllowModifyA)
00785 flags |= CV_SVD_MODIFY_A;
00786
00787 if (bReturnUTransposed)
00788 flags |= CV_SVD_U_T;
00789
00790 if (bReturnVTransposed)
00791 flags |= CV_SVD_V_T;
00792
00793 CvMat matrixA = cvMat(rows, columns, CV_64FC1, A->data);
00794 CvMat matrixW = cvMat(rows, columns, CV_64FC1, W->data);
00795
00796 if (U && V)
00797 {
00798 CvMat matrixU = cvMat(rows, rows, CV_64FC1, U->data);
00799 CvMat matrixV = cvMat(columns, columns, CV_64FC1, V->data);
00800
00801 cvSVD(&matrixA, &matrixW, &matrixU, &matrixV, flags);
00802 }
00803 else if (U)
00804 {
00805 CvMat matrixU = cvMat(rows, rows, CV_64FC1, U->data);
00806
00807 cvSVD(&matrixA, &matrixW, &matrixU, 0, flags);
00808 }
00809 else if (V)
00810 {
00811 CvMat matrixV = cvMat(columns, columns, CV_64FC1, V->data);
00812
00813 cvSVD(&matrixA, &matrixW, 0, &matrixV, flags);
00814 }
00815 else
00816 {
00817 cvSVD(&matrixA, &matrixW, 0, 0, flags);
00818 }
00819 }