2008年8月14日 星期四

OpenCV線性代數-cvSVD奇異值分解(2)

這邊就要簡單介紹cvSVD()的所有參數及用法,cvSVD()在"cxcore.h"裡面的參數分別被定義為

#define CV_SVD_MODIFY_A 1
#define CV_SVD_U_T 2
#define CV_SVD_V_T 4


第一個CV_SVD_MODIFY_A是將A矩陣的空間做填充,用空間換取時間的方式做加速的運算,而後面的CV_SVD_U_T,及CV_SVD_V_T則是單純的將U跟V做轉置.接著下面的程式拿非奇異矩陣做奇異值分解並且加上cvSVD()的參數.


非奇異矩陣奇異值分解
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

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

double Array1[]={1,3,3,-3,-5,-3,3,3,1};
int main()
{
    CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
    CvMat *W=cvCreateMat(3,3,CV_64FC1);
    CvMat *V=cvCreateMat(3,3,CV_64FC1);
    CvMat *U=cvCreateMat(3,3,CV_64FC1);
    CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
    CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);

    cvSetData(Matrix1,Array1,Matrix1->step);
    cvSVD(Matrix1,W,U,V,CV_SVD_MODIFY_A);

    printf("\nW\n");
    PrintMatrix(W,W->rows,W->cols);

    printf("\nU\n");
    PrintMatrix(U,U->rows,U->cols);
    printf("\nV\n");
    PrintMatrix(V,V->rows,V->cols);

    printf("\nValid\n");
    cvmMul(U,W,ResultMatrix);
    cvTranspose(V,V_T);
    cvmMul(ResultMatrix,V_T,ResultMatrix);
    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");
    }
}

執行結果:


上面使用了CV_SVD_MODIFY_A,由上面的非奇異矩陣得知,無法求得他的Eign Value及Eigen Vector,但是可以求得它的奇異值以及它的分解矩陣,並且藉由矩陣相乘的方式計算回原矩陣.計算及驗證的方式如下





而使用了CV_SVD_V_T這個參數則可以省略掉對V做cvTranspose()轉置的步驟.


cvSVD()使用CV_SVD_V_T參數
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


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

double Array1[]={1,3,3,-3,-5,-3,3,3,1};
int main()
{
    CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
    CvMat *W=cvCreateMat(3,3,CV_64FC1);
    CvMat *U=cvCreateMat(3,3,CV_64FC1);
    CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
    CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);

    cvSetData(Matrix1,Array1,Matrix1->step);
    cvSVD(Matrix1,W,U,V_T,CV_SVD_V_T);

    printf("\nW\n");
    PrintMatrix(W,W->rows,W->cols);

    printf("\nU\n");
    PrintMatrix(U,U->rows,U->cols);
    printf("\nV_T\n");
    PrintMatrix(V_T,V_T->rows,V_T->cols);

    printf("\nValid\n");
    cvmMul(U,W,ResultMatrix);
    cvmMul(ResultMatrix,V_T,ResultMatrix);
    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");
    }
}

執行結果:


上面的程式碼跟前面的差別,就是直接在cvSVD()內部將V矩陣轉置,可以直接將奇異值分解做驗證,而CV_SVD_U_T亦是直接將U矩陣在內部轉置.

cvSVD()
將任何的矩陣做奇異值分解,假如要分解的矩陣是m*n,則W矩陣CvMat資料結構輸入格式必須是m*n,U矩陣CvMat資料結構輸入格式必須是m*m,V矩陣CvMat資料結構輸入格式必須是n*n,cvSVD()第一個引數為輸入目標CvMat矩陣資料結構,第二個引數為輸出W矩陣CvMat資料結構,第三個引數為U矩陣CvMat資料結構,第四個引數為V矩陣CvMat資料結構,第五個引數為cvSVD()的參數,分別為CV_SVD_MODIFY_A,CV_SVD_U_T,CV_SVD_V_T.
cvSVD(輸入CvMat資料結構,輸出W矩陣CvMat結構,輸出U矩陣CvMat結構,輸出V矩陣CvMat結構,目標參數或代號)



0 意見:

Copyright 2008-2009,yester