OpenCV学习之矩阵操作
1. 矩阵创建
矩阵创建有多种方法,我们可以用cvCreateMat创建一个矩阵,该函数返回指向这个矩阵的指针,函数原型如下:
CvMat* cvCreateMat( int height, int width, int type );
该方法既分配了矩阵头空间,也分配了数据空间。这个方法是最常用的方法。
我们也可以使用cvCreateMatHeader函数只创建一个矩阵头,该函数返回指向这个矩阵的指针,函数原型如下:
CvMat* cvCreateMatHeader( int rows, int cols, int type );
注意这里只为矩阵头分配了空间,没有为矩阵的数据域分配空间。
你可以去看一下OpenCV的源代码,cvCreateMat包含了两步,一是头创建,二是数据域创建,函数源码如下:
CV_IMPL CvMat*
cvCreateMat( int height, int width, int type )
{
CvMat* arr = cvCreateMatHeader( height, width, type );
cvCreateData( arr );
return arr;
}
也可以使用cvInitMatHeader方法初始化一个矩阵头,注意这里只对矩阵头进行初始化,既不分配矩阵头空间,也不分配数据域空间,函数原型如下:
CvMat* cvInitMatHeader( CvMat* arr, int rows, int cols, int type, void* data, int step );
2. 矩阵释放
矩阵释放使用cvReleaseMat函数,函数原型如下:
void cvReleaseMat( CvMat** array );
3. 矩阵数据的访问
Learning OpenCV介绍了三种方法:
(1)简单的方法
得到矩阵的一个元素最简单的方法是利用宏CV_MAT_ELEM,该宏有四个参数,传入矩阵,待提取的元素类型,行和列。例如:
float element_3_2 = CV_MAT_ELEM(*mat, float, 3, 2);
设置矩阵的一个值可以使用宏CV_MAT_ELEM_PTR,例如:
float element_3_2 = 7.7;
*((float *)CV_MAT_ELEM_PTR(*mat, 3, 2)) = element_3_2;
注意这些宏每次调用时都重新计算指针,在计划顺序访问矩阵中的所有元素时,缺点尤为突出,这些宏只适合简单访问矩阵中的某个元素。
(2)复杂的方法
如果仅仅读取数据,使用cvGet*D函数族,cvGet*D函数族有:
CvScalar cvGet1D( const CvArr* arr, int idx );
CvScalar cvGet2D( const CvArr* arr, int y, int x );
CvScalar cvGetND( const CvArr* arr, const int* idx );
cvPtr*D函数族
cvPtr*D函数族有:
uchar* cvPtr1D( const CvArr* arr, int idx, int* _type );
uchar* cvPtr2D( const CvArr* arr, int y, int x, int* _type );
uchar* cvPtr3D( const CvArr* arr, int z, int y, int x, int* _type );
uchar* cvPtrND( const CvArr* arr, const int* idx, int* _type, int create_node, unsigned* precalc_hashval );
这些函数返回要访问元素的指针,我们可以利用这个指针进行一些算数运算后访问矩阵的其它元素。
(3)恰当的方法
恰当的方法就是利用矩阵的数据域指针自定义访问矩阵。例如累加三通道矩阵中所有的元素:
float sum(const CvMat* mat)
{
float s = 0.0f;
for (int row = 0; row < mat->rows; row++) {
const float *ptr = (const float *)(mat->data.ptr + row * mat->step);
for (col = 0; col < mat->cols; col++) {
s += *ptr++;
}
}
return (s);
}