OpenCV 累加一个三通道矩阵的所有元素
看了《学习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 累加一个三通道矩阵的所有元素相关推荐
- 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出。...
编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 题目描述 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 输入描述 编写程序输入一个5x5的矩阵 ...
- c语言 输入n*n矩阵,C语言函数 编程输入一个n*n矩阵中各元素的值,找出两条对角线上的元素之和...
题目: C语言函数 编程输入一个n*n矩阵中各元素的值,找出两条对角线上的元素之和 用函数怎么写 解答: #include #define N 5 void main() { \x09int matr ...
- opencv分离RGB三通道
注:本文非标准教程,仅是总结个人学习过程,可能存在纰漏,如有错误之处欢迎留言告知,非常感谢 本文用RGB通道来改变图像颜色. #include <iostream> #include &l ...
- opencv:把三通道图转换成灰度图、二值图
#include <opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<openc ...
- opencv学习笔记[9]:Opencv的基本数据类型和矩阵结构
一.基本数据类型: 1.CvPoint 图像中的点 Opevcv提供的数据类型中最简单的就是CvPoint. typedef struct CvPoint { int x; int y; } CvPo ...
- OpenCV学习笔记三-Mat数据结构
主要记录Mat数据结构的一些操作 P3 Mat 数据结构的一些操作 #include<opencv2/opencv.hpp> #include<iostream>using n ...
- 三通道图像转化为三通道,并将多通道图像混合
#include<cv.h> #include<highgui.h> #include<iostream> using namespace cv; using na ...
- python opencv二值化图像_python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘...
python opencv,读取彩色图像,提取三通道,图像二值化,提取图像的边缘 python opencv 1,读取图像 2,图像变矩阵 3,图像转灰度图像 4,彩色图像是3D数组 5,灰度图像是2 ...
- opencv笔记(三十一)——Mat 矩阵数据类型转换convertTo
一.数据类型转换 1.一般图像文件格式使用的是unsigned 8bits,对应的数据类型有:CV_8UC1.CV_8UC2,CV_8UC3 其中,CV_8UC3表示3通道8位的unsigned ch ...
- 【Opencv入门】RGB三通道直方图的计算与绘制
文章目录 一. 直方图概述 Overview of histogram 二.直方图的建立 Establishment of histogram 三.直方图的作用 The function of his ...
最新文章
- 自动驾驶感知系统盘点
- jsonProperty
- 如何快速实现 Wordpress 博客域名更换?
- SpringCloud微服务注册调用入门-路由网关
- 关于VGG模型文件的存放位置
- java图片上传并解析_java的图片上传详解
- 跨过虚拟化技术浪潮,这家企业快步入局云数据管理​
- VMware OVF 协议
- [笔记] 最大权闭合子图最大流最小割相关笔记
- 自动采集电影网站PHP源码
- PHP合并多个excel文件
- 还有什么服务器有无限连击,无限元宝动作类变态服有哪些
- 物联网网关神器 Kong ( 四 )- 利用 Konga 来配置生产环境安全连接 Kong
- 你还在迷茫?设计师前3年的瓶颈期要这样突破
- Altium Designer(四)排针类元件模型的创建
- npm ERR! code ERESOLVEnpm ERR! ERESOLVE could not resolve dependency
- php 判断时间是星期几,php如何判断当天星期几
- QCC304X/QCC514X DFU/OTA升级精讲
- 浪漫是浪漫,不浪漫也是浪漫
- ROS学习笔记(十三):Using Stamped datatypes with tf::MessageFilter