博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
学习OpenCV——关于三通道的CvMat的求和问题
阅读量:6802 次
发布时间:2019-06-26

本文共 3614 字,大约阅读时间需要 12 分钟。

  在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
rows; row++ ) {
6 const float* ptr = (const float*)(mat->data.ptr + row * mat->step);//获取第row行的首地址 7 for( col=0; col
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
rows; row++ ) {
for( col=0; col
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
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
rows; row++ ) {
2 const float* ptr = (const float*)(mat->data.ptr + row * mat->step);//获取第row行的首地址 3 for( col=0; col
cols; col++ ) {
4 s += *ptr+*(ptr+1)+*(ptr+2); 5 ptr += 3; 6 } 7 } 8 return( s ); 9 }

 

 

转载于:https://www.cnblogs.com/moondark/archive/2012/03/12/2392437.html

你可能感兴趣的文章
运维前线:一线运维专家的运维方法、技巧与实践1.8 运维自动化依赖的团队模型...
查看>>
《树莓派渗透测试实战》——第1章 树莓派和Kali Linux基础知识
查看>>
《圣殿祭司的ASP.NET4.0专家技术手册》----1-7 HTML5与CSS3的支持
查看>>
数据结构之链表
查看>>
八年了必须放手了,我不是你妈妈
查看>>
Eric S. Raymond 五部曲
查看>>
《Ansible权威指南 》一2.7 本章小结
查看>>
《iOS编程指南》——2.4节安装iOS SDK
查看>>
Comparing Mongo DB and Couch DB
查看>>
《配置管理最佳实践》——1.6 工具的选择
查看>>
前端工程师如何快速的开发一个微信JSSDK应用
查看>>
Apache Spark源码走读(九)如何进行代码跟读&使用Intellij idea调试Spark源码
查看>>
Android应用安全开发之浅谈网页打开APP
查看>>
后退时保存表单状态
查看>>
Python简介
查看>>
泛函编程(13)-无穷数据流-Infinite Stream
查看>>
XML与HTML
查看>>
find grep wc awk sed sort uniq split指令详解
查看>>
绩效管理功能扩展包
查看>>
#pragma的用法
查看>>