2008年7月15日 星期二

資料結構操作與運算-CvMat的標頭實作

CvMat的標頭資訊,跟IplImage的用法很類似,這邊就做一些簡單的實作.

簡單的CvMat標頭的製作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int main()
{
    CvMat *Matrix1=cvCreateMatHeader(10,10,CV_32FC1);
    cvCreateData(Matrix1);

    cvRange(Matrix1,30,130);

    for(int i=0;i<10;i++)
    {
        for(int j=0;j<10;j++)
        {
            printf("%.f ",cvGet2D(Matrix1,i,j).val[0]);
        }
        printf("\n");
    }
    system("pause");
    cvReleaseMatHeader(&Matrix1);
}

執行結果:


這邊用到的CvMat矩陣的標頭資訊,跟前面IplImage差不多,先用cvCreateMatHeader()創立標頭資訊及標頭空間,再用cvCrateData()創立矩陣空間,而cvCreateMat()就是等於cvCreateMatHeader()+cvCreateData(),只不過這邊用分開的方式創立了空間,cvRange()則是只能用在單通道float型別的CvMat矩陣結構上使用,功能是在做矩陣空間範圍內數據的增加,這邊創立了一個100*100的矩陣,而數據由30加到了130,再用cvGet2D()展示執行結果.

CvMat標頭檔製作2
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


float data[4][8];

int main()
{
    CvMat *Matrix1=cvCreateMatHeader(4,8,CV_32FC1);
    CvMat Matrix2;
    cvSetData(Matrix1,data,Matrix1->step);
    cvSet(Matrix1,cvRealScalar(30.1));

    cvInitMatHeader(&Matrix2,4,4,CV_32FC2,NULL,CV_AUTOSTEP);

    cvReshape(Matrix1,&Matrix2,2,4);
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            printf("(%.1f,%.1f) ",cvGet2D(&Matrix2,i,j).val[0],cvGet2D(&Matrix2,i,j).val[1]);
        }
        printf("\n");
    }
    system("pause");
    cvReleaseMatHeader(&Matrix1);
    free(&Matrix2);
}

執行結果:


上面的程式碼,則是標頭資訊的應用之一,兩個資料空間大小相同的矩陣,改變了它列跟欄以及通道的形狀,這邊是用到4(rows)*8(cols)*1(channel)的矩陣,改變成4(rows)*4(cols)*2(channels)的矩陣,利用標頭資訊的內容控制改變它的矩陣空間數據的形狀,因此,資料的排列就因此變形了,主要是用在兩個相同空間大小的矩陣的變換.這邊先用cvCreateMatHeader()創立一個float型別4*8矩陣通道一的標頭資訊,用cvSetData()設立矩陣資料空間,用vInitMatHeader()初始化Matrix2標頭資訊,為float型別4*4通道一的矩陣,接著用cvReshape()改變它的形狀,cvReshape()第三個引數是通道數,第四個引數則是列(rows)的數目.

cvCreateMatHeader()
創立CvMat資料結構的標頭空間及標頭資訊,這邊使用cvCreateMatHeader()後矩陣的資料空間仍為空.
cvCreateMatHeader(矩陣列數(rows)數據,矩陣欄(colunms)數數據,Cvmat資料結構參數)

cvRange()
遞增範圍數據,再矩陣內做範圍遞增的動作,必須用到float型別單通道浮點數的矩陣,第一個引數為目標結構,可為IplImage及CvMat結構,第二個引數為遞增開始值數據,第三個引數為遞增結束值數據.
cvRange(目標IplImage資料結構或CvMat資料結構,開始值數據,結束值數據)


cvInitMatHeader()
初始化矩陣標頭資訊,不包含CvMat標頭空間的創立,跟cvMat()差不多,但cvMat()包含矩陣空間的創立,第一個引數為選擇CvMat資料結構,第二個為列數(rows),第三個為欄數(colunms),第四個為CvMat資料結構矩陣參數,第五個為預設矩陣資料空間,再來是自動設立它的總寬度,由CV_AUTOSTEP則可以自動去計算它的總寬度.
cvInitMatHeader(CvMat資料結構,列數數據,欄數數據,CvMat結構參數,資料空間輸入,CV_AUTOSTEP);

cvReshape()
改變矩陣空間的形狀,為CvMat資料結構特有的函式,第一個引述為要改變的結構空間,可為IplImage及CvMat,第二個引數為輸出值,必須輸入CvMat的標頭資訊,第三個引數為改變通道數,第四個引數為改變的列數(rows).
cvReshape(IplImage資料結構或CvMat資料結構,CvMat標頭資訊,改變的通道數據,改變的列數據)

cvReleaseMatHeader()
釋放CvMat標頭記憶體空間,這邊cvReleaseMatHeader()被定義為

#define cvReleaseMatHeader cvReleaseMat

因此它跟cvReleaseMat()是一樣的.
cvReleaseMatHeader(CvMat標頭資料結構)



4 意見:

KJ 提到...

你好,我想請問一下
cvMat Matrix2;
cvInitMatHeader(&Matrix2,4,4,CV_32FC2,NULL,CV_AUTOSTEP);
為什麼要宣靠成這樣而不是cvMat *Matrix2呢?

另外,cvInitMatHeader()初始化矩陣標頭資訊,不包含CvMat標頭空間的創立,那第五個引數(資料空間輸入)如果有設值或者矩陣給它,會有整個完成的Mat資訊嗎?


謝謝,看您的文章對學習openCV實在幫助很大 : )

yester 提到...

cvMat *Matrix1; <--未給空間
cvMat Matrix2; <--已經配置一段空間

cvInitMatHeader()是直接給數值未做資料結構初始化,所以說給一個沒創立空間的Matrix1會出錯,但是,如果有用cvCreateMat()就會是正確的~

用Matrix2這種方式的好處,可以避免Memory leak,將同樣的變數一直用cvCreateMat()不斷的創造新的記憶體空間而忘了release,倒不如直接用cvMat Matrix2;這種方式來的安全,

第二個問題~ 是的XD,不過cvInitMatHeader(&Matrix2,4,4,CV_32FC1,Array,CV_AUTOSTEP);
的函式呼叫如果給int Array[2][8];
的矩陣,它還是會視為4*4的矩陣,因為他裡面是用Matrix2.step的方式來計算矩陣跳躍的空間

coolwaterld 提到...

void cvRange( CvArr* mat, double start, double end );

mat
The matrix to initialize. It should be single-channel 32-bit, integer or floating-point.
单通道32位整形也可以用cvRange

KJ 提到...

恩~差不多瞭解你的意思了,謝謝 :D

Copyright 2008-2009,yester