2008年7月24日 星期四

基本線性代數

說到矩陣的運算就不得不說到線性代數這個領域啦,線性代數為線性組合(Linear Combination)的代數運算,包含矩陣,行列式,向量,線性映射,對角化,解聯立線性方程式等,用矩陣的方式來表達,而線性代數用的是純係數的方式,係數的範圍為一個體(Field),簡稱F,矩陣為分佈於F的一個長方形陣列,而在體(Field)內單一的一個數據叫做純量(Scalar),純量並不是矩陣,而是一個值,與矩陣相乘稱為純量積.以下就將線性代數領域的部份用程式碼表達.

基本線性代數
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


CvMat *RowMatrix=cvCreateMat(3,1,CV_32FC1);
CvMat *ColMatrix=cvCreateMat(1,3,CV_32FC1);
CvMat *IdentityMatrix=cvCreateMat(3,3,CV_32FC1);

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

float Array[]={1,2,3,4,5,6,7,8,9};

int main()
{
    CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
    CvMat *Matrix2=cvCreateMat(3,3,CV_32FC1);
    CvMat *Matrix3=cvCreateMat(3,3,CV_32FC1);
    CvMat *Matrix4=cvCreateMat(3,3,CV_32FC1);
    CvMat *Matrix5=cvCreateMat(3,3,CV_32FC1);

    printf("Matirx:\n");
    cvSetData(Matrix1,Array,Matrix1->step);
    PrintMatrix(Matrix1,Matrix1->rows,Matrix1->cols);

    printf("\nRow Matirx:\n");
    cvGetRow(Matrix1,RowMatrix,1);
    PrintMatrix(RowMatrix,RowMatrix->rows,RowMatrix->cols);

    printf("\nColumn Matrix :\n");
    cvGetCol(Matrix1,ColMatrix,1);
    PrintMatrix(ColMatrix,ColMatrix->rows,ColMatrix->cols);

    printf("\nIdentity Matirx:\n");
    cvmSetIdentity(IdentityMatrix);
    PrintMatrix(IdentityMatrix,IdentityMatrix->rows,IdentityMatrix->cols);
    printf("==========================\n");

    printf("\nMatrix Add:\n");
    cvmAdd(Matrix1,Matrix1,Matrix2);
    PrintMatrix(Matrix2,Matrix2->rows,Matrix2->cols);

    printf("\nMatrix Sub:\n");
    cvmSub(Matrix1,IdentityMatrix,Matrix3);
    PrintMatrix(Matrix3,Matrix3->rows,Matrix3->cols);

    printf("\nMatrix Scalar Multiplication:\n");
    cvmScale(Matrix1,Matrix4,3);
    PrintMatrix(Matrix4,Matrix4->rows,Matrix4->cols);

    printf("\nMatrix Mul:\n");
    cvmMul(ColMatrix,RowMatrix,Matrix5);
    PrintMatrix(Matrix5,Matrix5->rows,Matrix5->cols);

    system("pause");

    cvReleaseMat(&Matrix1);
    cvReleaseMat(&Matrix2);
    cvReleaseMat(&Matrix3);
    cvReleaseMat(&Matrix4);
    cvReleaseMat(&Matrix5);
    cvReleaseMat(&RowMatrix);
    cvReleaseMat(&ColMatrix);
    cvReleaseMat(&IdentityMatrix);
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
    for(int i=0;i<Rows;i++)
    {
        for(int j=0;j<Cols;j++)
        {
            printf("%.f ",cvGet2D(Matrix,i,j).val[0]);
        }
        printf("\n");
    }
}
執行結果:


上面的資料結構Matrix1為最基本的矩陣,它可以表達成以下的線性組合
或是

一般都是用係數表示,而將它的列擷取下來稱為列矩陣(Row Matrix)或列向量(Row vector)


將它的行擷取下來稱為它的行矩陣(Column Matrix)或行向量(Column Vector)


而對角線為1的稱為單位矩陣(Identity Matrix)


而下面就是一般的矩陣加法


再來是矩陣減法


再來是矩陣的純量積(Scalar Mulitiplication)


矩陣乘法


在這邊除了矩陣乘法之外,其他的線性代數函式都可以用任意的矩陣參數來使用而要注意參數的資料型別的對應,而cvmMul()則只能用CV_32FC1的參數及float型別的矩陣資料,要不然會產生錯誤.

cvmAdd()
在"cvcompat.h"的函式庫被定義為

#define cvmAdd( src1, src2, dst ) cvAdd( src1, src2, dst, 0 )

因此跟cvAdd()是一樣的,不具有Mask功能,為矩陣專用函式.第一,第二個引數為輸入CvMat資料結構,第三個引數為CvMat輸出資料結構
cvmAdd(輸入CvMat資料結構,輸入CvMat資料結構,輸出CvMat資料結構)

cvmSub()
在"cvcompat.h"的函式庫被定義為

#define cvmSub( src1, src2, dst ) cvSub( src1, src2, dst, 0 )

因此跟cvSub()是一樣的,不具有Mask功能,為矩陣專用函式.第一,第二個引數為輸入CvMat資料結構,第三個引數為CvMat輸出資料結構
cvmSub(輸入CvMat資料結構,輸入CvMat資料結構,輸出CvMat資料結構)

cvmScale()
為矩陣的純量積運算,第一個引數為輸入CvMat資料結構,第二個引數為輸出CvMat資料結構,第三個引數為double型別純量數據.
cvmScale(輸入CvMat資料結構,輸出CvMat資料結構,double型別純量數據)

cvmMul()
為矩陣乘法運算,第一,第二個引數為輸入CvMat資料結構,第三個引數為CvMat輸出資料結構
cvmMul(輸入CvMat資料結構,輸入CvMat資料結構,輸出CvMat資料結構)



4 意見:

空白 提到...

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

請問下 Matrix1->step

這是指什麼意思呢

yester 提到...

在這篇有提到

CvMat資料結構

為一個CvMat矩陣欄長度的總byte數,因為要考慮到通道所以變成這樣表達

東之月 提到...

碰到個怪狀況 ... 不知道你會不會這樣
依照你的範例進行矩陣乘法 ..
[3*1] * [1*3] = [3*3]
這樣可以

但是如果改成
[3*3] * [3*1]
理論上應該得到[3*1]矩陣
但是會變成執行錯誤 ... 不知道你是否也會這樣

yester 提到...

應該是你程式有地方沒寫好吧XD

#include <cv.h>
#include <stdio.h>

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

float Array1[]={1,2,3,4,5,6,7,8,9};
float Array2[]={1,2,3};

int main()
{
    CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
    CvMat *Matrix2=cvCreateMat(3,1,CV_32FC1);
    CvMat *ResultMatrix=cvCreateMat(3,1,CV_32FC1);

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

    printf("\nMatrix Mul:\n");
    cvmMul(Matrix1,Matrix2,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("%.1f ",cvGet2D(Matrix,i,j).val[0]);
        }
        printf("\n");
    }
}

附上一個[3*3] * [3*1]可以執行的~
有可能是你ResultMatrix的格式沒打對吧我猜XD

Copyright 2008-2009,yester