OpenCV 中的三大数据类型:CvMat 类型
前言
本文将介绍 OpenCV 中的矩阵结构 CvMat 并提供几个很常用的矩阵使用方法。
更多的矩阵处理函数还请参阅相关资料。
CvMat 的类型定义
1 typedef struct CvMat 2 { 3 int type; // 数据类型 4 int step; // 行长度 5 int* refcount; /* 内部使用 */ 6 int hdr_refcount; /* 内部使用 */ 7 union // 指向数据区的指针 8 { 9 uchar* ptr; 10 short* s; 11 int* i; 12 float* fl; 13 double* db; 14 } data; 15 union // 行数 16 { 17 int rows; 18 int height; 19 }; 20 union // 列数 21 { 22 int cols; 23 int width; 24 }; 25 } CvMat;
CvMat 的创建方法
创建矩阵函数:
1 cvMat * cvCreateMat (int rows, int cols, int type);
rows:行数
cols:列数
type:数据类型,其格式一般为 CV_<比特数>(S|U|F)C<通道数>,比如 CV_32FC3 就表示 32 位浮点类型的 3 通道矩阵。
CvMat 中单个元素的存取方法
1. 可以使用宏 CV_MAT_ELEM () 来实现对矩阵某个元素的读取,如下代码访问矩阵中的第 3 行 2 列的元素:
1 float elem_3_2 = CV_MAT_ELEM (*mat, float, 3, 2);
其中,mat是 CvMat * 类型,float 是类型说明,最后两个参数是元素的行和列,该宏返回指定的元素的值。
2. 可以使用宏 CV_MAT_ELEM_PTR () 来实现对矩阵某个元素的设置,该宏返回指向指定元素的指针,如下代码修改矩阵中的第 3 行 2 列的元素:
1 *((float *)CV_MAT_ELEM_PTR (*mat, 3, 2)) = elem_3_2;
需要说明的是,获取到指向指定元素的指针后,还需要对这个指针进行强制转型方能正常使用。
CvMat 的遍历方法
如果遍历采用一个个取元素的方法,未免效率太慢。实际应用中,对矩阵的遍历常常采用指针遍历法,如下代码展示了对一个 CvMat 矩阵的遍历:
1 // 此头文件包含图像IO函数的声明 2 #include "highgui.h" 3 // 此头文件包含基本的图像处理函数和高级计算机视觉算法 4 #include "cv.h" 5 #include <iostream> 6 7 #define R 10 // 矩阵行 8 #define C 10 // 矩阵列 9 10 using namespace std; 11 12 int main (void) { 13 14 // 创建 R 行 C 列 32位单通道浮点类型的矩阵 15 CvMat *m1 = cvCreateMat ( R, C, CV_32FC1 ); 16 17 // 赋值变量 18 float s = 1.0f; 19 // 遍历矩阵并赋值 20 for (int i=0; i<R; i++) { 21 // 获取矩阵每行的行首地址,下面的data成员必须先取其ptr成员计算完偏移地址后,再强制转化为目标数据类型。 22 float *ptr = (float *)(m1->data.ptr + i * m1->step); 23 // 遍历子一维数组 24 for (int j=0; j<C; j++) { 25 ptr[j] = s++; 26 } 27 } 28 29 // 打印结果 30 for (int i=0; i<m1->rows; i++) { 31 float *ptr = (float *)(m1->data.ptr + i * m1->step); 32 for (int j=0; j<m1->cols; j++) { 33 printf("%7.2f", *ptr); 34 ptr++; 35 } 36 cout << endl; 37 } 38 cout << endl << endl; 39 40 getchar(); 41 42 return 1; 43 }
运行结果:
说明
1. 一般尽量创建浮点矩阵( F 型 ),别的类型值可以向上转型后存放进去。
2. 如果要遍历的是字符型( U S 型 )矩阵,那么遍历指针一定要设定为字符型的,等到取出的时候再向上转型/存进的时候向下转型即可。