2008年8月3日 星期日

OpenCV線性代數-cvEigenVV實作

cvEigenVV()為計算CvMat方陣的特徵值(Eigen Value)跟特徵向量(Eigen Vector)的函式,但是,OpenCV的Eigen Value跟Eigen Vector計算並不是一般性的用法,無法處理正常的特徵值跟特徵向量的計算,cvEigenVV()是使用到Jacobi Eigenvalue Algorithm的方法,輸入必須要對稱矩陣,輸入的對稱矩陣做Jacobi Transformation的轉換,這部份的資料就要參考數值分析(Numerical Recipes)的相關書籍了,而Jacobi Eigenvalue Algorithm有將Eigen Value重新Sort過,因此特徵值的排序會是由大到小排列,而不適用於很多矩陣對角化的解題應用.


cvEigenVV()實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

void PrintMatrix(CvMat *Matrix,int Rows,int Cols);

double Array1[]={2,3,0,3,5,-1,0,-1,2};

int main()
{
    CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
    CvMat *EigenValue_Row=cvCreateMat(3,1,CV_64FC1);
    CvMat *EigenValue=cvCreateMat(3,3,CV_64FC1);
    CvMat *EigenVector=cvCreateMat(3,3,CV_64FC1);
    CvMat *EigenVector_Invert=cvCreateMat(3,3,CV_64FC1);
    CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
    cvSetData(Matrix1,Array1,Matrix1->step);
    cvSetZero(EigenValue);

    cvEigenVV(Matrix1,EigenVector,EigenValue_Row,DBL_EPSILON);

    printf("\nThe EigenValue_Row is:\n");
    PrintMatrix(EigenValue_Row,EigenValue_Row->rows,EigenValue_Row->cols);

    printf("\nThe EigenVector is:\n");
    PrintMatrix(EigenVector,EigenVector->rows,EigenVector->cols);

    printf("\nThe EigenValue is:\n");
    cvSet2D(EigenValue,0,0,cvGet2D(EigenValue_Row,0,0));
    cvSet2D(EigenValue,1,1,cvGet2D(EigenValue_Row,1,0));
    cvSet2D(EigenValue,2,2,cvGet2D(EigenValue_Row,2,0));
    PrintMatrix(EigenValue,EigenValue->rows,EigenValue->cols);

    cvTranspose(EigenVector,EigenVector);
    cvmMul(EigenVector,EigenValue,ResultMatrix);
    cvInvert(EigenVector,EigenVector_Invert,CV_LU);
    cvmMul(ResultMatrix,EigenVector_Invert,ResultMatrix);

    printf("\nTo validate Matrix\n");
    PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);

    system("pause");

}

void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
    for(int i=0;i<Rows;i++)
    {
        for(int j=0;j<Cols;j++)
        {
            printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
        }
        printf("\n");
    }
}
執行結果:


由上面可以知道Eigen Value的排列方式為


而Eigen Vector的排列方式為


因此,要驗證是否可行,利用


的方法將它還原為對稱矩陣,則必須要將輸出的列矩陣補0讓它成為對角矩陣,並且將Eigen Vector矩陣做轉置,帶入驗證公式,輸出結果為原對稱矩陣,因此可以證明此函式及輸入值無誤

cvEigenVV()第一的引數為特徵向量(Eigen Vector)第二個引數為特徵值(Eigen Value)第三個引數為精確度,DBL_EPSILON為最小double型別精確度,而一般精確度的使用定義為

#define FLT_EPSILON 1.19209290E-07F
#define DBL_EPSILON 2.2204460492503131E-16

這可以來做浮點數的精確度比較運算使用.
而他的使用方式就如同下所述

bool IsEqual(double x,double y)
{
    if(x-y<DBL_EPSILON)
    {
        return true;
    }
    else
    {
        return false;
    }
}

double型別則對照DBL_EPSILON參數,float型別則對照FLT_EPSILON,而cvEigenVV()則可以自行定義它的精確度比較運算的大小.

cvEigenVV()
利用Jacobi Eigenvalue Algorithm法計算Eigen Value,Eigen Vector,輸入只能為對稱矩陣,輸出則是Eigen Value的列舉陣及Eigen Vector的列舉陣,第一個引數為要計算的CvMat資料結構對稱矩陣,第二個引數為CvMat資料結構的Eigen Value列舉陣,第三個引數是CvMat資料結構的Eigen Vector列舉陣,第四個引數為精確度比較運算的大小.
cvEigenVV(輸入CvMat資料結構對稱矩陣,輸出CvMat資料結構的EigenValue列舉陣,輸出CvMat資料結構的EigenVector列舉陣,浮點型別精準度誤差比較數值)



1 意見:

路人甲 提到...

這網誌真的是太讚了

原本就有在用opencv

不過還是有些函式不懂怎麼用

感恩

Copyright 2008-2009,yester