2008年8月19日 星期二

OpenCV線性代數-線性映射,矩陣變換

線性映射(Linear transformation),是由向量為基礎的映射函式,在OpenCV內標準的向量表達方式為通道的向量,也就是今天為一組<r,g,b>三通道所組成的圖形,則圖形內的<r,g,b>個別值則代表一個向量,cvTransform()則是為此而做的轉換,下面則是簡單的一個通道向量的運算


簡單線性映射實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


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

float Array1[]={4,1,0,2,1,1,3,2,1,1,4,1.5};
float Array2[]={2,1,2};
int main()
{
    CvMat *A=cvCreateMat(4,3,CV_32FC1);
    CvMat *x=cvCreateMat(1,1,CV_32FC3);
    CvMat *T_x=cvCreateMat(1,1,CV_32FC4);

    cvSetData(A,Array1,A->step);
    cvSetData(x,Array2,x->step);
    cvTransform(x,T_x,A);

    PrintMatrix(T_x,T_x->rows,T_x->cols,4);
    system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols,int Channels)
{
    for(int i=0;i<Rows;i++)
    {
        for(int j=0;j<Cols;j++)
        {
            for(int k=0;k<Channels;k++)
            {
                printf("%.2f ",cvGet2D(Matrix,i,j).val[k]);
            }
        }
        printf("\n");
    }
}

執行結果:




A矩陣則是叫轉移矩陣(Transition Matrix),可以專門在做基底座標變換的運用,這邊要特別注意的是,cvTransform()它拿通道來代替向量,而不是拿矩陣來代替向量,事實上,矩陣也可以作為向量的表達,但不適用於cvTransform().這邊cvTransform()輸入,x矩陣為通道三,而A則一定要輸入通道一的矩陣,輸出的T_x矩陣為通道四,而對於一個向量而言,此種運算方式叫做線性映射,如果對於一個矩陣圖形的話,則叫做矩陣變換(Matrix Transformation).

矩陣變換的部分,就拿RGB轉YCbCr的公式來實作,跟前面的線性映射不同的是,它直接拿通道三的矩陣來做色彩空間的轉換.


RGB轉YCbCr實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


float Array1[]={0.2989,0.5867,0.1140,-0.1687,-0.3312,0.5,0.5,-0.4183,-0.0816};
float Array2[]={0,128,128};

int main()
{
    CvMat *TransitionMatrix=cvCreateMat(3,3,CV_32FC1);
    CvMat *ShiftVector=cvCreateMat(3,1,CV_32FC1);

    IplImage *Image1=cvLoadImage("MineCar.jpg",1);
    IplImage *GrayImage1=cvLoadImage("MineCar.jpg",0);
    IplImage *YCbCrImage1=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,3);
    IplImage *YImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);
    IplImage *CbImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);
    IplImage *CrImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);

    cvSetData(TransitionMatrix,Array1,TransitionMatrix->step);
    cvSetData(ShiftVector,Array2,ShiftVector->step);

    cvTransform(Image1,YCbCrImage1,TransitionMatrix,ShiftVector);

    cvSplit(YCbCrImage1,YImage,CbImage,CrImage,0);

    cvNamedWindow("YImage",1);
    cvShowImage("YImage",YImage);
    cvNamedWindow("GrayImage",1);
    cvShowImage("GrayImage",GrayImage1);

    cvWaitKey(0);
}

原始圖片:


執行結果:


由上面線性映射的基礎來對一個通道三個圖形做矩陣變換,這邊將RGB的圖片藉由公式轉成YCbCr的格式,這個部分就叫做色彩空間的轉換,Y代表的是亮度,也就是灰階值,Cb則是藍色的色差,Cr則為紅色的色差,因此,這邊直接拿cvLoadImage()讀取灰階圖形來跟Y值圖形來做比較.中間有用到通道分割的函式cvSplit()則是要參考前面資料結構"通道的分割,合併與混合"的部份,cvTransform()的第四個引數則是對轉移矩陣計算後的數值結果做平移的運算.

cvTransform()
將圖形或矩陣做矩陣變換,矩陣變換的向量維度是以通道為基礎,也就是轉移矩陣會對通道向量做相乘而完成色彩空間的轉換,第四個引數則是對計算結果的向量做位移的調整,而轉移矩陣的m*n大小可以決定輸出通道的維度,這邊m代表輸入通道數,n代表輸出通道數.
cvTransform(輸入CvMat或IplImage資料結構,輸出CvMat或IplImage資料結構,CvMat轉移矩陣資料結構,CvMat平移向量資料結構)



2008年8月16日 星期六

OpenCV線性代數-cvSVBkSb奇異值倒回替代法

cvSVBkSb()為解線性系統解專用的,實際上它跟前面的cvSolve()的線性系統求解的奇異值法是一樣的東西,cvSolve()內部的CV_SVD參數它的計算方式實際上就是呼叫cvSVBkSb()這個函式,所以,用起來的方式差不多,在這邊簡單的做cvSVBkSb()的使用方法.


線性系統求解-奇異值倒回替代法
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


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

float Array1[]={-1,2,-1,3,1,-4,5,-5,-2,6,-5,7,-1,-4,11,-2};
float Array2[]={6,-7,7,7};
int main()
{
    CvMat *A=cvCreateMat(4,4,CV_32FC1);
    CvMat *b=cvCreateMat(4,1,CV_32FC1);
    CvMat *W=cvCreateMat(4,4,CV_32FC1);
    CvMat *U=cvCreateMat(4,4,CV_32FC1);
    CvMat *V=cvCreateMat(4,4,CV_32FC1);
    CvMat *x=cvCreateMat(4,1,CV_32FC1);

    cvSetData(A,Array1,A->step);
    cvSetData(b,Array2,b->step);
    cvSVD(A,W,U,V);
    cvSVBkSb(W,U,V,b,x,0);

    PrintMatrix(x,x->rows,x->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");
    }
}

在這邊,要用cvSVBkSb()之前就要先用到前面的cvSVD()了,在將cvSVD()奇異值分解的數值餵進cvSVBkSb()裡面解線性系統解,這邊奇異值倒回替代法用的是虛反矩陣的觀念,虛反矩陣則是在前面cvInvert()裡面有提到,而它的第四個引數為cvSVBkSb()的參數及代號,與cvSVD()相同,可輸入的參數為

#define CV_SVD_U_T 2
#define CV_SVD_V_T 4

分別代表U矩陣跟V矩陣輸入是否為轉置,如果不需要任何轉置輸入則將參數代號預設為0,而此題的線性系統,驗證及計算的方式如下










cvSVBkSb()
為線性系統求解的奇異值替代倒回法,對於一個無解的線性系統,使用奇異值替代倒回法可以求得近似解,但是使用cvSVBkSb()這個函式時必須要先做cvSVD()奇異值分解的計算,在將分解後的矩陣丟給cvSVBkSb()求線性系統的解,使用到的是虛反矩陣的概念,第一個引數為CvMat結構的W矩陣,第二個引數為CvMat結構的U矩陣,第三個引數為CvMat結構的V矩陣,前面的矩陣結構都必須經由cvSVD()奇異值分解計算而得,第四個引數為Ax的線性組合數據,第五個引數為x的解集合,第六個引數則是cvSVBkSb()的參數輸入,只有CV_SVD_U_T及CV_SVD_V_T或者是0(無參數)這三種.
cvSVBkSb(CvMat資料結構W矩陣輸入,CvMat資料結構U矩陣輸入,CvMat資料結構V矩陣輸入,CvMat資料結構b矩陣輸入,CvMat資料結構線性系統解集合x矩陣,目標參數或代號)



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結構,目標參數或代號)



2008年8月11日 星期一

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

奇異值分解(Singular Value Decomposition,SVD),可以說是對角化應用的特例,它具有與Eigen Value,Eigen Vector相同的特性,分解後向量的矩陣乘積可以還原為原矩陣,而他可以對奇異矩陣(Singular Matrix)做分解,亦可以對非奇異矩陣做分解.奇異矩陣的定義就是不能計算為反矩陣的矩陣,包括方陣,以及非方陣的長方形矩陣.而奇異值分解的計算它的數學定義為



它將奇異矩陣轉置後相乘,藉由這個方法計算出對稱矩陣,在對對稱矩陣做SVD分解,由上面可知,原矩陣大小為m*n,而W(Sigma)矩陣的舉陣大小必須為m*n,U的矩陣大小必須為m*m,而V的矩陣大小為n*n,它可以藉由矩陣矩陣相乘的方式算回原矩陣.

下面這個是拿2*3的奇異矩陣做奇異值分解


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


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

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

    cvSetData(Matrix1,Array1,Matrix1->step);

    cvSVD(Matrix1,W,U,V);

    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");
    }
}

執行結果:


上面的程式,利用了前面奇異值分解公式說明的方式,cvSVD()的內部運算,先將矩陣做轉置在相乘,求得對稱矩陣,在將該矩陣做奇異值分解,而它的W,U,V矩陣的大小皆不相同,W將會是原矩陣大小2*3,V則是2*2,U則會是3*3,因此利用公式倒回運算,可以計算出原矩陣,計算以及驗證的公式如下.





而對稱矩陣的奇異值分解,則是不需要再做轉置後相乘,直接做奇異值分解.


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


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

double Array1[]={2,-2,4,-2,2,-4,4,-4,8};
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);

    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");
    }
}

執行結果:


這是一個直接用對稱矩陣做奇異值分解的程式,奇異值分解很特別的地方,它對對稱矩陣做奇異值分解求得的結果為特徵值(Eigen Value)及特徵向量(Eigen Vector),但是相較於cvEigenVV()這兩個使用的是不同的演算法,而一般的矩陣則無法用cvSVD()求特徵值及特徵向量,上面的程式用cvSVD()分別求出它的W,U,V,在代回原公式做驗證,驗證的方法如下





驗證對稱矩陣奇異值分解




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列舉陣,浮點型別精準度誤差比較數值)



2008年8月1日 星期五

OpenCV線性代數-秩,線性系統求解(2)

在cvSolve()裡面,輸入的係數矩陣規定要方陣,那假如所求的線性系統不是方陣怎麼辦呢?那當然就是要用補0了方式填充成方陣,使用的方法請看以下程式碼.


解線性方程式4
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

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

float Array1[]={1,1,0,2,1,0,3,2,0};
float Array2[]={1,3,4};
int main()
{
    CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
    CvMat *Matrix2=cvCreateMat(3,1,CV_32FC1);
    CvMat *SolveSet=cvCreateMat(3,1,CV_32FC1);

    cvSetData(Matrix1,Array1,Matrix1->step);
    cvSetData(Matrix2,Array2,Matrix2->step);
    cvSolve(Matrix1,Matrix2,SolveSet,CV_SVD);

    PrintMatrix(SolveSet,SolveSet->rows,SolveSet->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");
    }
}

執行結果:



線性系統判斷


上面的程式是尾端補0,因為這個線性系統只存在兩個未知數,三個方程式,要給它弄成方陣,則只好假設有第三個未知數存在,但係數為0,而只要是需要補0的線性系統運算,全部都需要用CV_SVD來解,LU是無法解的.再來,下面是整欄補零的範例.


解線性方程式5
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

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

float Array1[]={1,1,1,1,2,0,0,0,0};
float Array2[]={4,6,0};
int main()
{
    CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
    CvMat *Matrix2=cvCreateMat(3,1,CV_32FC1);
    CvMat *SolveSet=cvCreateMat(3,1,CV_32FC1);

    cvSetData(Matrix1,Array1,Matrix1->step);
    cvSetData(Matrix2,Array2,Matrix2->step);
    cvSolve(Matrix1,Matrix2,SolveSet,CV_SVD);

    PrintMatrix(SolveSet,SolveSet->rows,SolveSet->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");
    }
}

執行結果:


線性系統判斷


這個線性系統是四個未知數,三個方程式,很顯然的是無限解,用SVD的方法的話就會任意給一個可行解,而至於cvSolve()的另外一個參數CV_SVD_SYM,則是線性系統對對稱係數矩陣的加速算法,也是跟前面相關的程式碼同樣的用法,這邊不再累述.

cvSolve()
為解線性方程式的函式,可以對唯一解,無解,無限解,而無限解的問題會給予一個答案,無解的問題則是用CV_SVD參數則可得到近似解,而無限解的問題則用cvSolve()參數可以得到可行解.第一個引數為CvMat係數矩陣,第二個引數為線性方程式的線性組合解,第三個引數為代數的解集合,第四個為解線性方程的參數輸入,分別為CV_LU,CV_SVD,CV_SVD_SYM,與求反矩陣的函式相同參數.
cvSolve(CvMat係數矩陣結構,CvMat結構線性組合解,CvMat結構代數解集合,輸入計算參數或代號)



Copyright 2008-2009,yester