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平移向量資料結構)



1 意見:

匿名 提到...

IplImage 的色彩格式應該是BGR,可是這邊卻沒有轉換成RGB就直接相乘,這樣的原因在哪??不太懂,謝謝!!

Copyright 2008-2009,yester