opencvmat存储内存(Opencv中数据结构Mat的相关属性)

seosqwseo1周前 (09-11)测评日记13

一、opencv编程中错误提示:不存在从mat到cvmat适当的转换函数。

opencv中常见的与图像*作有关的数据容器有Mat,cvMat和IplImage,这三种类型都可以代表和显示图像,但是,Mat类型侧重于计算,数学性较高,openCV对Mat类型的计算也进行了优化。而CvMat和IplImage类型更侧重于“图像”,opencv对其中的图像*作(缩放、单通道提取、图像阈值*作等)进行了优化。在opencv2.0之前,opencv是完全用C实现的,但是,IplImage类型与CvMat类型的关系类似于面向对象中的继承关系。实际上,CvMat之上还有一个更抽象的基类----CvArr,这在源代码中会常见。

1. IplImage

opencv中的图像信息头,该结构体定义:

View Code

typedef struct _IplImage

{

int nSize;

int ID;

int nChannels;

int alphaChannel;

int depth;

char colorModel[4];

char channelSeq[4];

int dataOrder;

int origin;

int align;

int width;

int height;

struct _IplROI*roi;

struct _IplImage*maskROI;

void*imageId;

struct _IplTileInfo*tileInfo;

int imageSize;

char*imageData;

int widthStep;

int BorderMode[4];

int BorderConst[4];

char*imageDataOrigin;

} IplImage;

dataOrder中的两个取值:交叉存取颜色通道是颜色数据排列将会是BGRBGR...的交错排列。分开的颜色通道是有几个颜色通道就分几个颜色平面存储。roi是IplROI结构体,该结构体包含了xOffset,yOffset,height,width,coi成员变量,其中xOffset,yOffset是x,y坐标,coi代表channel of interest(感兴趣的通道),非0的时候才有效。访问图像中的数据元素,分间接存储和直接存储,当图像元素为浮点型时,(uchar*)改为(float*):

View Code

二、opencv 中 Mat 数据结构的用法

#include"stdafx.h"

#include<string>

#include<iostream>

#include<opencv2/opencv.hpp>

using namespace std;

using namespace cv;

int _tmain(int argc, _TCHAR* argv[])

{

//创建一个用1+3j填充的 7 x 7复矩阵-----1

Mat M(7, 7, CV_32FC2, Scalar(1,3));

//现在将 M转换为100 x 60的CV_8UC(15)的矩阵,旧内容将会被释放

M.create(100, 60, CV_8UC(15));//不能为矩阵设置初值

//第 5行,乘以 3,加到第 3行,

M.row(3)= M.row(3)+ M.row(5)* 3;

//现在将第7列**到第1列, M.col(1)= M.col(7);//这个不能实现,对列*作时要新建一个Mat

Mat M1= M.col(1);

M.col(7).copyTo(M1);

//创建一种新的 320 x 240图像-----2

Mat img(Size(320,240), CV_8UC3, Scalar::all(255));

string strWindowName="ShowImage";

namedWindow(strWindowName, WINDOW_AUTOSIZE);

imshow(strWindowName, img);

waitKey(0);

//选择ROI(region of interest)

Mat roi(img, Rect(10, 10, 100, 100));

//填充(0,255,0)的ROI(这是RGB空间中的绿色),320 x 240原始图像将被修改

roi= Scalar(0, 255, 0);

imshow(strWindowName, img);

waitKey(0);

//获取数组中的子块-----3

Mat A= Mat::eye(10, 10, CV_32S);

//提取 A的1(含)到 3(不包含)列

Mat B= A(Range::all(), Range(1, 3));

//提取 B的5(含)到 9(不包含)行,即 C~ A(Range(5,9),Range(1,3))

Mat C= B(Range(5, 9), Range::all());

Size size;

Point ofs;

C.locateROI(size, ofs);//使用locateROI()计算子数组在主容器数组中的相对的位置

cout<<size.width<<""<<size.height<<""<<ofs.x<<""<<ofs.y<<endl;

//快速初始化小矩阵-----4

double m[3][3]={{1, 2, 3},{1, 2, 5},{3, 4, 6}};

Mat M2= Mat(3, 3, CV_64F, m);//.inv();

Mat E= Mat::eye(4, 4, CV_64F);

cout<<"E="<<endl<<""<<E<<endl;

Mat O= Mat::ones(2, 2, CV_32F);

cout<<"O="<<endl<<""<<O<<endl;

Mat Z= Mat::zeros(3,3, CV_8UC1);

cout<<"Z="<<endl<<""<<Z<<endl;

//IplImage、Mat、CvMat互转-----5

IplImage*img1= cvLoadImage("aa.jpg", 2| 4);

Mat mtx(img1);//IplImage*-> Mat,新的Mat类型与原来的IplImage类型共享图像数据,转换只是创建一个Mat矩阵头// or: Mat mtx= img1;

CvMat oldmat= mtx;//Mat-> CvMat//只是创建矩阵头,而没有**数据,oldmat不用手动释放

CV_Assert((oldmat.cols== img1->width)&&(oldmat.rows== img1->height)&&(oldmat.data.ptr==(uchar*)img1->imageData)&&(oldmat.step== img1->widthStep));

imshow(strWindowName, mtx);

waitKey(0);

cvNamedWindow(strWindowName.c_str(), 0);

cvShowImage(strWindowName.c_str(),&oldmat);

cvWaitKey(0);

IplImage img2= mtx;//Mat->IplImage//只是创建图像头,而没有**数据,img2不用手动释放

cvShowImage(strWindowName.c_str(),&img2);

cvWaitKey(0);

Mat mat3(&oldmat);//CvMat->Mat

imshow(strWindowName, mat3);

waitKey(0);

cvDestroyWindow(strWindowName.c_str());

cvReleaseImage(&img1);

//创建 3 x 3双精度恒等矩阵-----6

Mat M3=(Mat_<double>(3,3)<<1,0,0, 0,1,0, 0,0,1);

//访问数组元素-----7

M2.at<double>(0, 0)+= 10.f;

double sum= 0;//计算元素和,方法一

for(int i=0; i<M2.rows; i++)

{

const double*Mi= M2.ptr<double>(i);

for(int j=0; j<M2.cols; j++)

{

sum+= std::max(Mi[j], 0.);

}

}

cout<<sum<<endl;

sum= 0;//计算元素和,方法二

int cols=M2.cols, rows= M2.rows;

if(M2.isContinuous())

{

cols*= rows;

rows= 1;

}

for(int i=0; i<rows; i++)

{

const double*Mi= M2.ptr<double>(i);

for(int j=0; j<cols; j++)

{

sum+= std::max(Mi[j], 0.);

}

}

cout<<sum<<endl;

sum= 0;//计算元素和,方法三

MatConstIterator_<double> it= M2.begin<double>(), it_end= M2.end<double>();

for(; it!= it_end;++it)

{

sum+= std::max(*it, 0.);

}

cout<<sum<<endl;

return 0;

}

三、Opencv中数据结构Mat的相关属性

搬运自本人 CSDN博客:《Opencv中数据结构Mat的相关属性》

以上摘自OpenCV 2.4.9的官方文档opencv2refman.pdf。

以前虽然能够比较熟练的使用OpenCV,但是近感觉其实笔者自己对OpenCV的底层数据结构Mat与IplImage都不怎么熟悉……由于笔者比较反感总是需要管理内存的IplImage,所以对Mat数据结构做一下学习工作还是有必要的。

官方说明文档opencv2refman.pdf中,写出了Mat的定义如下:

下面笔者将从几个方面总结Mat数据结构的主要组成。

参考**:

《OpenCV中对Mat里面depth,dims,channels,step,data,elemSize和数据地址计算的理解》

《OpenCV Mat的常见属性》

《OpenCV学习笔记(四十)——再谈OpenCV数据结构Mat详解》

参考文档:

《opencv2refman.pdf》

如上面的Mat定义源码,Mat类中有很多重要的数据类型成员。

下面进行简单的列举。

把这四个数据成员放在一起,是因为这四个数据成员相互之间有关系。

数据的存储一直都是个值得关注的问题,所以数据元素存储的位数和范围就十分重要了。depth就体现了每一个像素的位数,即深度。

Mat中包含的图像深度如下所示:

另外还需要注意:大部分OpenCV的函数支持的数据深度只有8位和32位,所以尽量使用CV_64F。

channels表示了矩阵拥有的通道数量,这个比较容易理解:

type表示矩阵中元素的类型(depth)与矩阵的通道个数(channels),可以理解成上面的depth与channels的综合说明。type是一系列预定义的常量,命名规则如下:

<code>CV_+位数+数据类型+通道数</code>

具体有如下值:

表格中,行代表了通道数量channels,列代表了图像深度depth。

例如CV_8UC3,可以拆分为:

注:type一般是在创建Mat对象时设定,若要去的Mat的元素类型,可以不使用type,使用depth。

elemSize表示了矩阵中每一个元素的数据大小,单位是字节。公式如下:

<code>elemSize= channels* depth/ 8</code>

例如type== CV_16SC3,则elemSize= 3* 16/ 8= 6 Bytes。

elemSize1表示了矩阵元素的一个通道占用的数据大小,单位是字节。公式如下:

<code>elemSize= depth/ 8</code>

例如type== CV_16SC3,则elemSize1= 16/ 8= 2 Bytes。

使用OpenCV处理图像时,普遍的处理方式便是遍历图像,即访问所有的图像像素点。但有的算法还需要访问目标像素的邻域,所以这时候就需要了解访问Mat数据元素地址的方式。

假设有矩阵M,则数据元素的地址计算公式如下:

$$ addr(M_{i_{0}, i_{1},... i_{m-1}})= M.data+ M.step[0]* i_{0}+ M.step[1]* i_{1}+...+ M.step[M.dims- 1]* i_{M_{dims-1}}$$

如果是二维数组,则上述公式就简化成:

$$ addr(M_{i,j})= M.data+ M.step[0]* i+ M.step[1]* j$$

注:式中m= M.dims,即矩阵的维度。

假设存在一个二维矩阵如下图所示:

上面是一个3× 4的矩阵。此时我们按照数据类型为CV_8U, CV_8UC3的情况,分别对其进行讨论。

首先假设其数据类型为CV_8U,也就是单通道的uchar类型,则可以得出上面的数据成员情况分别为:

若假设其数据类型为CV_8UC3,也就是三通道的uchar类型,则可以得出上面的数据成员情况分别为:

假设存在一个三维矩阵如下图所示:

上面是一个3× 4× 6的矩阵。假设其数据类型为CV_16SC4,此时对其进行讨论。

关于OpenCV地址访问方法及效率的部分,请见笔者的博文《OpenCV像素点邻域遍历效率比较,以及访问像素点的几种方法》。

相关文章

海信会议平板电视86英寸会议电视视频会议平板一体机触摸电视电子白板智能商用大屏显示价格多少钱

海信会议平板电视86英寸会议电视视频会议平板一体机触摸电视电子白板智能商用大屏显示价格多少钱

很多小伙伴在关注海信会议平板电视86英寸会议电视视频会议平板一体机触摸电视电子白板智能商用大屏显示怎么样?质量好不好?使用测评如何?本文综合已购用户的客观使用分享和相应的优...

创维电视43H3测评怎么样

创维电视43H3测评怎么样

很多小伙伴在关注创维电视43H3怎么样?质量好不好?使用测评如何?本文综合已购用户的客观使用分享和相应的优惠信息,为大家推荐一款高性价比的产品,一起来看看吧。...

六品堂课程专拍链接质量好不好

六品堂课程专拍链接质量好不好

很多小伙伴在关注六品堂课程专拍链接怎么样?质量好不好?使用测评如何?本文综合已购用户的客观使用分享和相应的优惠信息,为大家推荐一款高性价比的产品,一起来看看吧。...

酷狗KUGOUPB11质量好不好

酷狗KUGOUPB11质量好不好

很多小伙伴在关注酷狗KUGOUPB11怎么样?质量好不好?使用测评如何?本文综合已购用户的客观使用分享和相应的优惠信息,为大家推荐一款高性价比的产品,一起来看看吧。...

华为HUAWEIFreeBuds图文测评

华为HUAWEIFreeBuds图文测评

很多小伙伴在关注华为HUAWEIFreeBuds怎么样?质量好不好?使用测评如何?本文综合已购用户的客观使用分享和相应的优惠信息,为大家推荐一款高性价比的产品,一起来看看吧...

云麦好轻体脂秤3SEmini充电智能电子秤家用体重秤口碑好不好

云麦好轻体脂秤3SEmini充电智能电子秤家用体重秤口碑好不好

很多小伙伴在关注云麦好轻体脂秤3SEmini充电智能电子秤家用体重秤怎么样?质量好不好?使用测评如何?本文综合已购用户的客观使用分享和相应的优惠信息,为大家推荐一款高性价比...