2008年7月5日 星期六

資料結構操作與運算-CvMat資料結構

再來簡單的介紹CvMat矩陣資料結構,這邊矩陣資料結構就比IplImage資料結構簡單些.

CvMat資料結構程式實作
#include <cv.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    float Array[]={1,2,3,4,5,6,7,8,9,10,11,12};
    CvMat Matrix1;
    Matrix1=cvMat(3,4,CV_32FC1,Array);

    printf("The type is : %d\n",Matrix1.type);
    printf("The depth is : %d\n",cvCvToIplDepth(Matrix1.type));
    printf("The step is : %d\n",Matrix1.step);
    printf("The rows is : %d\n",Matrix1.rows);
    printf("The cols is : %d\n",Matrix1.cols);
    cvmSet(&Matrix1,1,1,50);
    printf("The (1,1) is : %.1f\n\n",cvmGet(&Matrix1,1,1));

    for(int i=0;i<3;i++)
    {
        for(int j=0;j<4;j++)
        {
            printf("%.1f\n",Matrix1.data.fl[i*Matrix1.cols+j]);
        }
    }

    system("pause");
}

執行結果:


一開始,用一個一維陣列填入資訊,使用cvMat()初始化CvMat資料結構的矩陣型態,給它通道1的二維陣列,這裡製作了一個3*4的矩陣資料結構,而實際上,CvMat仍然是存在一維陣列裡的,要看裡面的資料則必須要像IplImage資料結構的使用方法一樣,這個程式使用了通道1的矩陣結構,32bits空間大小,列為3欄為4,Matrix1.type就是這個矩陣CV_8UC1的參數數據代號,是經由OpenCV的內部公式代換出來的,cvCvToIplDepth()則是可以藉由公式轉換回它的bit數(32bits),Matrix1.step則是矩陣空間的cols*參數型別byte數*Channel數也就是它二維陣列欄(Colunm)的總bytes長度,CvMat可以用cvmGet()跟cvmSet()存取數據,但是他這邊只能限定用float(32bits)跟double(64bits)的型別,其他uchar,int,short都不能用,但是CvMat可以用迴圈直接存取的方式,而當使用了迴圈存取數據的方法,因為CvMat資料結構是使用union聯集變數的方式,因此數據可以直接跟uchar,short,int,float,double型別通用,data底下分別代表的變數名稱為ptr(uchar*),s(short*),i(int*),fl(float*),db(double*),但是要注意的是,cvMat()的陣列餵什麼資料型別進去就要用什麼樣的資料型別讀出來.


+號以下代表OpenCV常用型別,-號以下表示OpenCV內部使用的數據型別

下面是CvMat資料結構讀取3個通道的個別矩陣質實做,與前面的IplImage資料結構相似.

CvMat資料結構讀取矩陣資料
#include <cv.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    uchar Array[]={1,1,1,2,2,2,3,3,3,4,4,4,
                          5,5,5,6,6,6,7,7,7,8,8,8,
                          9,9,9,10,10,10,11,11,11,12,12,12};

    uchar Channel1[3][4];
    uchar Channel2[3][4];
    uchar Channel3[3][4];

    CvMat Matrix1;
    Matrix1=cvMat(3,4,CV_8UC3,Array);

    for(int i=0;i<3;i++)
    {
        for(int j=0;j<4*3;j=j+3)
        {
            Channel1[i][(int)j/3]=Matrix1.data.ptr[i*Matrix1.cols*3+j];
            Channel2[i][(int)j/3]=Matrix1.data.ptr[i*Matrix1.cols*3+j+1];
            Channel3[i][(int)j/3]=Matrix1.data.ptr[i*Matrix1.cols*3+j+2];
        }
    }
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<4;j++)
        {
            printf("%d\n",Channel3[i][j]);
        }
    }
    system("pause");
}

執行結果:


由上面的實作,CvMat資料結構的矩陣資料就可以輕易的讀出來啦,要注意的是,使用uchar型別的話data就要用ptr,要不然讀出來的資料是錯誤的,在去考慮它的通道個數來讀取資料,因此3個通道的矩陣就可以很輕易的讀出來了.

cvMat()
初始化CvMat矩陣資料結構,給它二維陣列的維度,第一個為列(row),第二個為欄(column),第三個引數為矩陣參數,第四個引數為一維陣列的資料輸入,矩陣參數的種類為

CV_8UC1 CV_8SC1 CV_16UC1 CV_16SC1 CV_32SC1 CV_32FC1 CV_64FC1
CV_8UC2 CV_8SC2 CV_16UC2 CV_16SC2 CV_32SC2 CV_32FC2 CV_64FC2
CV_8UC3 CV_8SC3 CV_16UC3 CV_16SC3 CV_32SC3 CV_32FC3 CV_64FC3
CV_8UC4 CV_8SC4 CV_16UC4 CV_16SC4 CV_32SC4 CV_32FC4 CV_64FC4


參數的意義則要去參考前面的命名規則
cvMat(row數目,col數目,矩陣參數,一維陣列數據)

cvCvToIplDepth()
輸入CvMat的矩陣參數數據,可以得知它的深度,也就是一個矩陣被宣告的空間大小,可以參考變數對應的部份做適當的分配
cvCvToIplDepth(CvMat矩陣參數代號數據)

cvmSet()
設立CvMat資料結構內的數值,設立的數值要為double型別,但是它只限訂單通道矩陣使用.
cvmSet(CvMat資料結構,row列的數據,col欄的數據,double型別數值)

cvmGet()
取得CvMat資料結構內的數值,取得的數值為double型別,但是它只限訂單通道使用.
cvmGet(CvMat資料結構,row列的數據,col欄的數據)



3 意見:

匿名 提到...

第二个程序里定义了两遍i,j

匿名 提到...

這樣寫沒有錯。
i和j宣告只在這個迴圈內有效!

匿名 提到...

cvCvToIplDepth()
找不到識別項
有人跟我一樣嗎?

Copyright 2008-2009,yester