• opencv_mat


    在Learning OpenCV书中,讲到一个基础数据类型CvMat,其中有一段程序:

     1 Example 3-9. Summing all of the elements in a three-channel matrix
    2 float sum( const CvMat* mat ) {
    3
    4 float s = 0.0f;
    5 for(int row=0; row<mat->rows; row++ ) {
    6 const float* ptr = (const float*)(mat->data.ptr + row * mat->step);//获取第row行的首地址
    7 for( col=0; col<mat->cols; col++ ) {
    8 s += *ptr++;
    9 }
    10 }
    11 return( s );
    12 }

      不知是我理解错了,还是书中的注释错了,“Summing all of the elements in a three-channel matrix”,我觉得是对三通道CvMat中的所有数据进行求和,按我之前的编写风格,这个函数应该是这样:

    Example 3-9. Summing all of the elements in a three-channel matrix
    float sum( const CvMat* mat ) {

    float s = 0.0f;
    float* ptr=(float*) cvPtr2D(mat, 0, 0); //获取该三通道CvMat的首地址(这一句未经测试),将三通道看成是二通道

    for(int row=0; row<mat->rows; row++ ) {
    for( col=0; col<mat->cols; col++ ) {
    s += *ptr+*(ptr+1)+*(ptr+2);//将整个CvMat看成一个二维矩阵,则矩阵中每个元素是个三维向量,将它们累加
    ptr += 3;//通道为3,则自加3可到达CvMat矩阵中的下个元素
    }
    }
    return( s );
    }

      自己构建一个三通道矩阵,为测试方便,假设其为一个3*3的三通道矩阵:

    ( 1,  2,  3)  (11, 12, 13)  (21, 22, 23)
    (31, 32, 33) (41, 42, 43) (51, 52, 53)
    (61, 62, 63) (71, 72, 73) (81, 82, 83)

    //用代码构建如下


    CvMat* mat = cvCreateMat(3,3,CV_32FC3);//矩阵元素为三通道浮点数
    cvZero(mat);//将矩阵置0


    //----------为矩阵元素赋值-----------------

    //获得矩阵元素(0,0)的指针
    float *p = (float*)cvPtr2D(mat, 0, 0);
    //为矩阵赋值
    for(int i = 0; i < 9; i++)
    {
    //为每个通道赋值
    *p = (float)i*10;
    p++;
    *p = (float)i*10+1;
    p++;
    *p = (float)i*10+2;
    p++;
    }

      经过测试,书中的程序得到的结果是279,即如下数的和:

    ---------------
    |( 1, 2, 3) | (11, 12, 13) (21, 22, 23)
    |(31, 32, 33) | (41, 42, 43) (51, 52, 53)
    |(61, 62, 63) | (71, 72, 73) (81, 82, 83)
    ---------------

      即仅仅求了一个3*3 float矩阵的值,严格的说是矩阵中每行第一个元素的三通道元素和。

      我们可以对其进行进一步剖析,先看CvMat的申明:

     1 typedef struct CvMat
    2 {
    3 int type;
    4 int step;
    5 int* refcount;
    6 union
    7 {
    8 uchar* ptr;
    9 short* s;
    10 int* i;
    11 float* fl;
    12 double* db;
    13 } data;
    14 #ifdef __cplusplus
    15 union
    16 {
    17 int rows;
    18 int height;
    19 };
    20 union
    21 {
    22 int cols;
    23 int width;
    24 };
    25 #else
    26 int rows;
    27 int cols;
    28 #endif
    29 } CvMat;

         在大多数情况下,你需要使用最有效率的方式来访问矩阵中的数据。如果使用函数界面来访问数据,效率比较低,你应该使用指针方式来直接访问矩阵中数据。特别是,如果你想遍历矩阵中所有元素时,就更需要这样做了。
        在用指针直接访问矩阵元素时,就需要格外注意矩阵结构体中的step成员。该成员是以字节为单位的每行的长度。而矩阵结构体的cols或width就不适合此时使用,因为为了访问效率,矩阵中的内存分配上,是以每四个字节做为最小单位的。因此如果一个矩阵的宽度是三个字节,那么就会在宽度上分配四个字节,而此时每行最后一个字节会被忽略掉。所以我们用step则会准确地按行访问数据。
        我们可以通过以下例子,看一下rows,cols,height,width,step的数据,你可以通过改变矩阵的元素类型定义,来查看step的改变:

     1 #pragma comment(lib,"cxcore.lib")
    2 #include"cv.h"
    3 #include<stdio.h>
    4 void main()
    5 {
    6 //矩阵元素为三通道8位浮点数
    7 CvMat *mat=cvCreateMat(3,3,CV_32FC3 );
    8 printf("rows=%d,cols=%d,height=%d,width=%d,step=%d ",mat->rows,mat->cols,mat->height,mat->width,mat->step);
    9
    10 }
    //输出为rows=3,cols=3,height=3,width=3,step=36

      如果我们的矩阵存储的是浮点型(或整数类型)数据,此时矩阵中每个元素占4字节,则如果我们用float类型指针指向下一行时,我们实际上要用float类型指针挪动step/4的长度,因为float类型指针每挪动一个单位就是4个字节长度。
        如果我们的矩阵存储的是double类型数据,此时矩阵中每个元素占8字节,则如果我们用double类型指针指向下一行时,我们实际上要用double类型指针挪动step/8的长度,因为double类型指针每挪动一个单位就是8个字节长度。
      在书上源码中:

    const float* ptr = (const float*)(mat->data.ptr + row * mat->step);//获取第row行的首地址

    这里只是获得一个首地址而已,然后在结下来的循环里,它仅仅累加了mat->cols,并不正确,应该改为:

    1 for(int row=0; row<mat->rows; row++ ) {
    2 const float* ptr = (const float*)(mat->data.ptr + row * mat->step);//获取第row行的首地址
    3 for( col=0; col<mat->cols; col++ ) {
    4 s += *ptr+*(ptr+1)+*(ptr+2);
    5 ptr += 3;
    6 }
    7 }
    8 return( s );
    9 }
  • 相关阅读:
    maven 常用编译
    java 秒时间格式化
    git clone 带用户名密码
    Filebeat占用内存和CPU过高问题排查
    新的一周,全新的开始.
    vs2008 打开aspx文件时设计界面死机情况的解决
    php面试题及答案
    JQuery 对html控件操作总结
    网页常用Javascript
    针对修改php_ini不起作用的方案
  • 原文地址:https://www.cnblogs.com/mataiyuan/p/7745422.html
Copyright © 2020-2023  润新知