Learning OpenCV 第三章:初識OpenCV學習總結
【注】不同的OpenCV版本會有所不同。
OpenCV的基本資料型別
結構 | 成員 | 意義 |
CvPoint | int x, y | 影象中的點 |
CvPoint2D32f | float x, y | 二維空間中的點 |
CvPoint3D32f | ffloat x, y, z | 三維空間中的點 |
CvSize | int width, height | 影象的尺寸 |
CvRect | int x, y, width, height | 影象的部分割槽域 |
CvScalar | double 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) 引數意義如下:Parametersmat | A pointer to the matrix header to be initialized |
rows | Number of rows in the matrix |
cols | Number of columns in the matrix |
type | Type of the matrix elements, see cvCreateMat . |
data | Optional: data pointer assigned to the matrix header |
step | Optional: 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區域。