正确的方式
前面介绍的一些读取和写入矩阵数据的方式,实际上,你可能很少会使用它们。因为,在大多数情况下,你需要使用最有效率的方式来访问矩阵中的数据。如果使用以上的函数界面来访问数据,效率比较低,你应该使用指针方式来直接访问矩阵中数据。特别是,如果你想遍历矩阵中所有元素时,就更需要这样做了。
在用指针直接访问矩阵元素时,就需要格外注意矩阵结构体中的step成员。该成员是以字节为单位的每行的长度。而矩阵结构体的cols或width就不适合此时使用,因为为了访问效率,矩阵中的内存分配上,是以每四个字节做为最小单位的。因此如果一个矩阵的宽度是三个字节,那么就会在宽度上分配四个字节,而
此时每行最后一个字节会被忽略掉。所以我们用step则会准确地按行访问数据。
我们可以通过以下例子,看一下rows,cols,height,width,step的数据,你可以通过改变矩阵的元素类型定义,来查看step的改变:
#pragma comment(lib,"cxcore.lib")
#include"cv.h"
#include<stdio.h>
void main()
{
//矩阵元素为三通道32位浮点数
CvMat *mat=cvCreateMat(3,3,CV_32FC3 );
printf("rows=%d,cols=%d,height=%d,width=%d,step=%d/n",mat->rows,mat->cols,mat->height,mat->width,mat->step);}
如果我们的矩阵存储的是浮点型(或整数类型)数据,此时矩阵中每个元素占4字节,则如果我们用float类型指针指向下一行时,我们实际上要用float类型指针挪动step/4的长度,因为float类型指针每挪动一个单位就是4个字节长度。
如果我们的矩阵存储的是double类型数据,此时矩阵中每个元素占8字节,则如果我们用double类型指针指向下一行时,我们实际上要用double类型指针挪动step/8的长度,因为double类型指针每挪动一个单位就是8个字节长度。
我们重新看一下CvMat类型的数据结构定义,其中,data就是数据部分,指向data的指针可以是多种数据类型的:
typedef struct CvMat {
int type;
int step;
int* refcount; // for internal use only
union {
uchar* ptr;
short* s;
int* i;
float* fl;
double* db;
} data;//数据部分
union {
int rows;
int height;
};
union {
int cols;
int width;
};
} CvMat;
我们可以通过为矩阵赋值,和读取的例子,查看怎样使用step:
#pragma comment(lib,"cxcore.lib")
#include"cv.h"
#include<stdio.h>
void main()
{
//矩阵元素为三通道8位浮点数
CvMat *mat=cvCreateMat(3,3,CV_32FC3 );
float *p;
int row,col;
for(row=0; row< mat->rows; row++)
{
p = mat->data.fl + row * (mat->step/4);
for(col = 0; col < mat->cols; col++)
{
*p = (float) row+col;
*(p+1) = (float) row+col+1;
*(p+2) =(float) row+col+2;
p+=3;
}
}for(row = 0; row < mat->rows; row++)
{
p = mat->data.fl + row * (mat->step/4);
for(col = 0; col < mat->cols; col++)
{
printf("%f,%f,%f/t",*p,*(p+1),*(p+2));
p+=3;
}
printf("/n");
}
}
如果我们使用的指针类型为uchar*类型,则事情可能会简单一些,不用考虑step/4,step/8等类似情况,我们推荐用这种方式。如下例所示:
#pragma comment(lib,"cxcore.lib")
#include"cv.h"
#include<stdio.h>
void main()
{
//矩阵元素为三通道8位浮点数
CvMat *mat=cvCreateMat(3,3,CV_32FC3 );
float *p;
int row,col;
for(row=0; row< mat->rows; row++)
{
p = (float*)(mat->data.ptr + row * mat->step);
for(col = 0; col < mat->cols; col++)
{
*p = (float) row+col;
*(p+1) = (float) row+col+1;
*(p+2) =(float) row+col+2;
p+=3;
}
}for(row = 0; row < mat->rows; row++)
{
p = (float*)(mat->data.ptr + row * mat->step);
for(col = 0; col < mat->cols; col++)
{
printf("%f,%f,%f/t",*p,*(p+1),*(p+2));
p+=3;
}
printf("/n");
}
}