看了《学习OpenCV》,发现例3-9代码有问题,就找了这篇文章: http://www.cnblogs.com/moondark/archive/2012/03/12/2392437.html   以下内容转自这篇文章。

在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 matrixfloat 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 __cplusplus15 union16 {17 int rows;18 int height;19 };20 union21 {22 int cols;23 int width;24 };25 #else26 int rows;27 int cols;28 #endif29 } 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\n",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  }

转载于:https://www.cnblogs.com/JieForest/p/3598580.html

OpenCV 累加一个三通道矩阵的所有元素相关推荐

  1. 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出。...

    编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 题目描述 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 输入描述 编写程序输入一个5x5的矩阵 ...

  2. c语言 输入n*n矩阵,C语言函数 编程输入一个n*n矩阵中各元素的值,找出两条对角线上的元素之和...

    题目: C语言函数 编程输入一个n*n矩阵中各元素的值,找出两条对角线上的元素之和 用函数怎么写 解答: #include #define N 5 void main() { \x09int matr ...

  3. opencv分离RGB三通道

    注:本文非标准教程,仅是总结个人学习过程,可能存在纰漏,如有错误之处欢迎留言告知,非常感谢 本文用RGB通道来改变图像颜色. #include <iostream> #include &l ...

  4. opencv:把三通道图转换成灰度图、二值图

    #include <opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<openc ...

  5. opencv学习笔记[9]:Opencv的基本数据类型和矩阵结构

    一.基本数据类型: 1.CvPoint 图像中的点 Opevcv提供的数据类型中最简单的就是CvPoint. typedef struct CvPoint { int x; int y; } CvPo ...

  6. OpenCV学习笔记三-Mat数据结构

    主要记录Mat数据结构的一些操作 P3 Mat 数据结构的一些操作 #include<opencv2/opencv.hpp> #include<iostream>using n ...

  7. 三通道图像转化为三通道,并将多通道图像混合

    #include<cv.h> #include<highgui.h> #include<iostream> using namespace cv; using na ...

  8. python opencv二值化图像_python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘...

    python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘 python opencv 1,读取图像 2,图像变矩阵 3,图像转灰度图像 4,彩色图像是3D数组 5,灰度图像是2 ...

  9. opencv笔记(三十一)——Mat 矩阵数据类型转换convertTo

    一.数据类型转换 1.一般图像文件格式使用的是unsigned 8bits,对应的数据类型有:CV_8UC1.CV_8UC2,CV_8UC3 其中,CV_8UC3表示3通道8位的unsigned ch ...

  10. 【Opencv入门】RGB三通道直方图的计算与绘制

    文章目录 一. 直方图概述 Overview of histogram 二.直方图的建立 Establishment of histogram 三.直方图的作用 The function of his ...

最新文章

  1. 自动驾驶感知系统盘点
  2. jsonProperty
  3. 如何快速实现 Wordpress 博客域名更换?
  4. SpringCloud微服务注册调用入门-路由网关
  5. 关于VGG模型文件的存放位置
  6. java图片上传并解析_java的图片上传详解
  7. 跨过虚拟化技术浪潮,这家企业快步入局云数据管理​
  8. VMware OVF 协议
  9. [笔记] 最大权闭合子图最大流最小割相关笔记
  10. 自动采集电影网站PHP源码
  11. PHP合并多个excel文件
  12. 还有什么服务器有无限连击,无限元宝动作类变态服有哪些
  13. 物联网网关神器 Kong ( 四 )- 利用 Konga 来配置生产环境安全连接 Kong
  14. 你还在迷茫?设计师前3年的瓶颈期要这样突破
  15. Altium Designer(四)排针类元件模型的创建
  16. npm ERR! code ERESOLVEnpm ERR! ERESOLVE could not resolve dependency
  17. php 判断时间是星期几,php如何判断当天星期几
  18. QCC304X/QCC514X DFU/OTA升级精讲
  19. 浪漫是浪漫,不浪漫也是浪漫
  20. ROS学习笔记(十三):Using Stamped datatypes with tf::MessageFilter

热门文章

  1. 转:linux下挂载移动硬盘
  2. 计算机网络中为什么引入IP地址?
  3. 春节7天新增病毒54万 钓鱼欺诈成最大威胁
  4. Linux下find命令实例
  5. java中输入输出总结
  6. Python 之操作so动态库
  7. history指令显示日期时间
  8. typedef struct引起的结构体问题
  9. 小辣椒android密码怎样开,小辣椒手机忘记密码怎么恢复出厂设置
  10. go -生成pb文件 -下