Learning OpenCV 第三章:初識OpenCV學習總結

【注】不同的OpenCV版本會有所不同。

OpenCV的基本數據類型

結構成員意義
CvPointint x, y 圖像中的點
CvPoint2D32ffloat x, y二維空間中的點
CvPoint3D32fffloat x, y, z三維空間中的點
CvSizeint width, height圖像的尺寸
CvRectint x, y, width, height圖像的部分區域
CvScalardouble val[4]RGBA的值,其中“A”表示透明度

其中,cvScalar有三個構造函數:

1.cvScalar(),它需要一到四個參數,並將這些參數傳遞給數組val[]中的相應元素。

2.cvRealScalar(), 它需要一個參數,並將這個參數傳遞給val[0].

3.cvScalarAll(), 它需要一個參數,並且val[]中4個元素都會被設置成這個參數。

矩陣和圖像類型

OpenCV提供了大量使用的圖像操作符,包括縮放圖像,單通道提取,找出特定通道的最大最小值,兩個圖像求和,對圖像進行閾值操作等等。

三種圖像的類的層次結構:CvArr、CvMat、IplImage

實際上,IplImage由CvMat派生,而CvMat由CvArr派生。

CvArr,可以被是爲一個抽象基類,CvMat由它派生。在函數原型中,會經常看到CvArr(CvArr*),當它出現時,便可以將CvMat*或者IplImage*傳遞到程序。

CvMat矩陣結構

【注意】在OpenCV中沒有向量結構

矩陣元素可以是32位浮點型數據(CV_32FC1),或者無符號的8位三元組的整型數據(CV_8UC3),或者是無數的其他類型的元素。可以改變其中的通道數,如單通道:CV_32FC1,雙通道:CV_32FC2,三通道:CV_32FC3。

CvMat結構:矩陣頭


type struct CvMat{

int * refcount;
int step;//行數據長度,用字節表示而不是整型或者浮點型長度int type;//矩陣元素類型,32位浮點數CV_32FC1/無符號8位三元組CV_8UC3

union {

int height;//高度 int rows;//行數 }; union { int cols;//列數 int width;//寬度 }; union { double * db; float * fl;int * i; uchar * ptr;//無符號字符指針,範圍是0-255 short * s; }data;}CvMat;

矩陣創建方法:

1.最常用的是cvCreateMat(),它由多個原函數組成,如:cvCreateMatHeader()和cvCreateData()。cvCreateMatHeader()函數創建CvMat結構,不爲數據分配內存,而cvCreateDate()函數只負責數據的內存分配。

2.函數cvCloneMat(CvMat*),它依據一個現有矩陣創建一個新矩陣。當這個矩陣不需要時,可以調用cvReleaseMat(CvMat*)釋放它。

矩陣的創建與釋放:

//Create a new rows by cols matrix of type 'type'.
//通過列數來創建“type”類型的新行
CvMat* cvCreateMat(int rows, int cols, int type);

//Create only matrix header without allocating data.
//只創建矩陣頭而不分配數據內存
CvMat* cvCreateMatHeader(int rows, int cols, int type);

//Initialize header on existing CvMat structer
//在現有的CvMat結構上初始化矩陣頭

CvMat* cvInitMatHeader(CvMat * mat,
  int rows,
  int cols,
  int type,
  void * data = NULL,
  int step = 0x7fffffff 
 ) 

Initializes a pre-allocated matrix header.

初始化一個預分配的矩陣頭。

This function is often used to process raw data with OpenCV matrix functions.

For example, the following code computes the matrix product of two matrices, stored as ordinary arrays:

以下是兩個矩陣乘積的示例:

double a[] = { 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12 };
double b[] = { 1, 5, 9,
2, 6, 10,
3, 7, 11,
4, 8, 12 };
double c[9];
CvMat Ma, Mb, Mc ;
cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a);
cvInitMatHeader(&Mb, 4, 3, CV_64FC1, b);
cvInitMatHeader(&Mc, 3, 3, CV_64FC1, c);
cvMatMulAdd(&Ma, &Mb, 0, &Mc);
// the c array now contains the product of a (3x4) and b (4x3)
參數意義如下:Parameters
matA pointer to the matrix header to be initialized
rowsNumber of rows in the matrix
colsNumber of columns in the matrix
typeType of the matrix elements, see cvCreateMat .
dataOptional: data pointer assigned to the matrix header
stepOptional: full row width in bytes of the assigned data. By default, the minimal possible step is used which assumes there are no gaps between subsequent rows of the matrix.
//Like cvInitMatHeader() but allocate CvMat as well.
//類似cvInitMatHeader()但是需要分配
CvMatInline constructor. No data is allocated internally!!!//不會自動分配內存!!!
(Use together with cvCreateData, or use cvCreateMat instead to get a matrix with allocated data)

//Allocate a new matrix just like the matrix 'mat'
//分配一個新的矩陣類似於‘mat’矩陣
CvMat* cvCloneMat(const cvMat mat);
【注】:函數cvCloneMat()和其他的OpenCV包含單詞'clone'的函數,不僅創建一個和輸入頭同樣的頭,也分配各自的數據區並將數據複製到新對象。

//Free the matrix 'mat', both header and data
//釋放一個矩陣,包括它的頭部和數據。
void cvReleaseMat(CvMat** mat);
矩陣數據的存取

簡單的方法:從矩陣中得到一個元素最簡單的方法是利用宏CV_MAT_ELEM()。分別傳入四個參數:待提取的矩陣、待提取元素的元素類型、元素所在的行數、列數。返回的是一個數值。有一個類似的宏:CV_MAT_ELEM_PTR(),返回指向這個元素的指針。若果需要對數據進行額外操作(比如同時讀取和設置數據),直接調用CV_MAT_ELEM_PTR()即可。

注:雖然這些宏容易使用,但每次調用的時候要通過指針進行多次尋址,所以不是最佳辦法。

麻煩的方法:使用cvPtr*D()和cvGet*D()函數族。對於cvPtr*D()來說返回的是一個指向所需元素的指針;對於cvGet*D()來說,返回的是矩陣元素的實際值。

以cvPtr1D爲例:

uchar* cvPtr1D (

const CvArr * arr,//矩陣指針,輸入的矩陣

int idx0,//表示索引的整數值
int * type = NULL //輸出值(矩陣元素)的類型
)

注:CvArr*是隻作爲函數參數使用的元類型,它表示該函數有時接受多種類型的矩陣,例如IplImage*、CvMat*等。通過分析頭的前4個字節,在運行時確定特定數組的類型。在c++接口,擔任輸入/輸出矩陣類型的角色。

對於cvGet*D()函數族:

double cvGetReal1D (

const CvArr * arr,

int idx0 
)

CvScalar cvGet1D (

const CvArr * arr,

int idx0 
)

使用這些函數的時候會有很大空間的浪費,所以只有在認爲這種方法比較方便或高效時才使用它們,否則最好使用cvPtr*D。

使用cvPtr*D()函數族還有另外一個原因,即可以用這些指針函數訪問矩陣中的特定的點,然後由這個點出發,用指針的算數運算得到指向矩陣中其他數據的指針。在多通道矩陣中,通道是連續的。

IplImage數據結構

typedef struct _IplImage {
int align;
int alphaChannel;
int BorderConst [4];
int BorderMode [4];
char channelSeq [4];
char colorModel [4];
int dataOrder;
int depth;//以比特爲單位的像素深度
int height;
int ID;//版本(=0)
char * imageData;//指向圖像數據的指針
char * imageDataOrigin;
void * imageId;
int imageSize;
struct _IplImage * maskROI;
int nChannels;
int nSize;//尺寸
int origin;//0-左上角原點,1-左下角原點
struct _IplROI * roi;
struct _IplTileInfo * tileInfo;
int width;
int widthStep;//行長
}IplImage;

注:不常用參數通常被忽略。

重要參數:感興趣的區域(ROI)。ROI的思想是:一旦設定ROI,通常用作於整幅圖像的函數變回只對ROI所表示的子圖像進行操作。

要設置或取消ROI,就要使用cvSetImageROI()和cvResetImageROI()。如果想設置ROI,可以使用函數cvSetImageROI(),併爲其傳遞一個圖像指針和矩形,而取消ROI,只需要爲函數cvResetImageROI()傳遞圖像指針。通過cvRestImageROI()函數釋放ROI是非常重要的,否則,將只顯示ROI區域。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章