通道和維度
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
首先說一下對矩陣維度和通道的理解:
維:體現爲座標。
通道:
對於這樣一個數組矩陣:
float data[18] =
{
30, 60, 40, 60, 50, 40,
67, 88, 55, 33, 22, 97,
59, 69, 32, 46, 25, 45
};
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
單通道顯示的話,就是這樣:
所以,單通道:可以理解爲:一個元素中含有1個數字。
雙通道就是把數組中每兩個數(如30和60)結合在一起,如:
雙通道可以
所以,雙通道:可以理解爲:一個元素中含有2個數字。
以此類推:三通道可以;理解爲一個元素中有3分數字。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
打印雙通道矩陣實例:
#include "highgui.h"
#include "cv.h"
int main()
{
float data[18] =
{
30, 60, 40, 60, 50, 40,
67, 88, 55, 33, 22, 97,
59, 69, 32, 46, 25, 45
};
CvMat mat;
cvInitMatHeader(&mat, 3, 3, CV_32FC2, data);
for (int y = 0; y < mat.rows; y++)
{
for (int x = 0; x < mat.cols; x++)
{
//CvScalar value = cvGetRealND(&mat, y, x,z);三維
CvScalar value = cvGet2D(&mat, y, x);
printf("(%f %f)", value.val[0], value.val[1]);
}
printf("\n");
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
實例解釋:
cvInitMatHeader()函數:用來初始化Mat結構體;
cvInitMatHeader( CvMat* arr, int rows, int cols,int type, void* data, int step )
參數解釋:
arr:CvMat結構體;
rows: 行數;
cols:列數;
type: 矩陣元素類型(可以是32位浮點型(CV_32FC1)或者是無符號的8位三元組的整形數據(CV_8UC3)或者其他類型);
這個也是改通道數的參數:如單通道(CV_32FC1),雙通道(CV_32FC2),三通道(CV_32FC3);
data:矩陣數組;
step: 步長,默認是: 一行數據所佔的字節數(int min_step = arr->cols*pix_size)。
cvGet2D()函數:對多通道二維矩陣訪問。(多通道三維:cvGet3D(),多通道多維:cvGetND()等一系列:cvGet*D函數);
cvGetReal1D():對單通道一維矩陣訪問,(單通道三維:cvGetReal3D(),單通道多維:cvGetRealND()等一系列:cvGetReal*D函數);*
這種訪問方式比較慢因爲涉及到壓棧和出棧,如果矩陣較大的話耗費的時間也很多。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
下面介紹一種更有效率的訪問方式,用指針訪問矩陣元素:
//單通道形式訪問矩陣元素
int main()
{
float data[18] =
{
30, 60, 40, 60, 50, 40,
67, 88, 55, 33, 22, 97,
59, 69, 32, 46, 25, 45
};
CvMat mat;
cvInitMatHeader(&mat, 3, 6, CV_32FC1, data);
int y = 2, x = 3;
for (y = 0; y < mat.rows; y++)
{
float* p_float = (float*)(mat.data.ptr + y*mat.step);
//mat.data.ptr:矩陣數組第一個數字。
//mat.step:步長(矩陣一行數字所佔的字節數)。
for (x = 0; x < mat.cols; x++)
{
float value = *(p_float + x);
printf("(%f)", value);
}
printf("\n");
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
//二通道矩陣數據讀取
int main()
{
float data[18] =
{
30, 60, 40, 60, 50, 40,
67, 88, 55, 33, 22, 97,
59, 69, 32, 46, 25, 45
};
CvMat mat;
cvInitMatHeader(&mat, 3, 3, CV_32FC2, data);
int y = 2, x = 3;
int nchannel = 2;
for (y = 0; y < mat.rows; y++)
{
float* p_float = (float*)(mat.data.ptr + y*mat.step);
for (x = 0; x < mat.cols; x++)
{
float value[2];
value[0] = *(p_float + x*nchannel);
value[1] = *(p_float + x*nchannel + 1);
//這裏加1是加一個float型的步長。
printf("(%f %f)", value[0],value[1]);
}
printf("\n");
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CvMat矩陣結構
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
typedef struct CvMat
{
int type;
int step;
/* for internal use only */
int* refcount;
int hdr_refcount;
union
{
uchar* ptr;
short* s;
int* i;
float* fl;
double* db;
} data;
#ifdef __cplusplus
union
{
int rows;
int height;
};
union
{
int cols;
int width;
};
#else
int rows;
int cols;
#endif
}
CvMat;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
此類信息通常被稱作爲矩陣頭。很多程序是區分矩陣頭和數據體的,後者是各個data成員所指向的內存位置。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
矩陣的創建和釋放:
創建一個新的矩陣,分配矩陣空間::
CvMat* cvCreateMat(int rows, int cols,int type);
例程:
CvMat* M = cvCreateMat(4,4,CV_32FC1);
創建一個矩陣頭,,不分配空間:
CvMat* cvCreateMatHeader(int rows,int cols,int type);
初始化已存在的CvMat結構體:
CvMat* cvInitMatHeader
(
CvMat *mat,
int row,
int clos,
int type;
voud *data = NULL;
int step = CV_AUTOSTEP
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
初始化一個矩陣,但是不分配空間:
CvMat cvMat
(
int rows,
int cols,
int type,
void* data = NULL
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
用一個矩陣初始化另外一個矩陣,也就是將一個矩陣的複製到另外一個矩陣上去:
CvMat* cvCloneMat(const cvMat* mat);
例:
CvMat* M1 = cvCreateMat(4,4,CV_32FC1);
CvMat* M2;
M2=cvCloneMat(M1);
釋放矩陣空間:
例:
CvMat* M = cvCreateMat(4,4,CV_32FC1);
cvReleaseMat(&M);
上面我們用介紹通道和維所用到的矩陣就是通過:
用固定數據創建一個Opencv矩陣。
矩陣數據的存取
1,這是一個簡單的方法:利用宏CV_MAT_ELSEM(),這個宏(傳入矩陣,待提取的元素類型,行,列4個參數)(注意:行列是從0開始算的)
利用宏讀取矩陣的值(簡單但慢):
int main()
{
float data[18] =
{
30, 60, 40, 60, 50, 40,
67, 88, 55, 33, 22, 97,
59, 69, 32, 46, 25, 45
};
CvMat mat;
cvInitMatHeader(&mat, 3, 6, CV_32FC1, data);
float element_3_2 = CV_MAT_ELEM(mat, float, 0, 2);
cout << element_3_2 << endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
利用宏寫矩陣的值:
int main()
{
float data[18] =
{
30, 60, 40, 60, 50, 40,
67, 88, 55, 33, 22, 97,
59, 69, 32, 46, 25, 45
};
CvMat mat;
cvInitMatHeader(&mat, 3, 6, CV_32FC1, data);
float element = 7.7;
*((float*)CV_MAT_ELEM_PTR(mat, 2, 4)) = element;
float element_3_2 = CV_MAT_ELEM(mat, float, 2, 4);
cout << element_3_2 << endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
但是這種使用宏的方法有個缺點,在每次調用宏的時候都要重新計算指針,即使宏使用起來容易,但是慢,所以不是存取矩陣的最好方法。
指針訪問矩陣結構(麻煩):
利用宏只能訪問1維和2維的數組,下面列舉cvPtr*D和cvGet*D等函數。
cvPtr*D可以是:cvPtr1D(一維),cvPtr2D(二維),cvPtr3D(三維),cvPtrND(多維),
cvGet*D也類似有這系列函數。
uchar* cvPtr1D(
const CvArr* arr, //訪問矩陣
int idx0, //元素索引,也就是在數組中的座標
int* type = NULL//元素類型
);
uchar* cvPtr2D(
const CvArr* arr,
int idx0,
int idx1,
int* type = NULL
);
uchar* cvPtr3D(
const CvArr* arr,
int idx0,
int idx1,
int idx2,
int* type = NULL
);
uchar* cvPtrND(
const CvArr* arr,
int* idx,
int* type = NULL,
int create_node = 1,
unsigned* precalc_hashval = NULL
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
實例:
//指針訪問矩陣結構
int main()
{
float vals[] = { 1, 2, 3, 4 };
CvMat* rotmat = cvCreateMat(2, 2, CV_32FC1);
cvInitMatHeader
(
rotmat,
2,
2,
CV_32FC1,
vals
);
float *p = (float*)cvPtr2D(rotmat, 1, 0);
cout << *p << endl;
return 0;
}
cvGet*D系列函數返回的是
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
建立自己的指針訪問(恰當的方法):
#include "highgui.h"
#include "cv.h"
int main()
{
float data[18] =
{
30, 60, 40, 60, 50, 40,
67, 88, 55, 33, 22, 97,
59, 69, 32, 46, 25, 45
};
CvMat mat;
cvInitMatHeader(&mat, 3, 3, CV_32FC2, data);
for (int y = 0; y < mat.rows; y++)
{
for (int x = 0; x < mat.cols; x++)
{
//CvScalar value = cvGetRealND(&mat, y, x,z);三維
CvScalar value = cvGet2D(&mat, y, x);
printf("(%f %f)", value.val[0], value.val[1]);
}
printf("\n");
}
return 0;
}