分类: OpenCv 2012-02-29 14:165388人阅读评论(2)收藏举报
byte优化图像处理数据结构matrixvector
一、Mat类型:矩阵类型,Matrix。
在openCV中,Mat是一个的密集数据数组。可以用来处理向量和矩阵、图像、直方图等等常见的数据。 Mat有3个重要的方法:
1、Mat mat = imread(const String* filename); 读取图像 2、imshow(const string frameName, InputArray mat); 显示图像
3、imwrite (const string& filename, InputArray img); 储存图像
Mat类型较CvMat与IplImage类型来说,有更强的矩阵运算能力,支持常见的矩阵运算。在计算密集型的应用当中,将CvMat与IplImage类型转化为Mat类型将大大减少计算时间花费。 A.Mat -> IplImage
同样只是创建图像头,而没有复制数据。 例: // 假设Mat类型的imgMat图像数据存在 IplImage pImg= IplImage(imgMat); B.Mat -> CvMat
与IplImage的转换类似,不复制数据,只创建矩阵头。 例: // 假设Mat类型的imgMat图像数据存在 CvMat cvMat = imgMat;
二、CvMat类型与IplImage类型:“图像”类型
在openCV中,Mat类型与CvMat和IplImage类型都可以代表和显示图像,但是,Mat类型侧重于计算,数学性较高,openCV对Mat类型的计算也进行了优化。而CvMat和IplImage类型更侧重于“图像”,openCV对其中的图像操作(缩放、单通道提取、图像阈值操作等)进行了优化。
补充:IplImage由CvMat派生,而CvMat由CvArr派生即CvArr -> CvMat -> IplImage CvArr用作函数的参数,无论传入的是CvMat或IplImage,内部都是按CvMat处理。 1.CvMat
A.CvMat-> IplImage
IplImage* img = cvCreateImage(cvGetSize(mat),8,1); cvGetImage(matI,img); cvSaveImage(\"rice1.bmp\B.CvMat->Mat
与IplImage的转换类似,可以选择是否复制数据。 Mat::Mat(const CvMat* m, bool copyData=false);
在openCV中,没有向量(vector)的数据结构。任何时候,但我们要表示向量时,用矩阵数据表示即可。
但是,CvMat类型与我们在线性代数课程上学的向量概念相比,更抽象,比如CvMat的元
素数据类型并不仅限于基础数据类型,比如,下面创建一个二维数据矩阵:
CvMat* cvCreatMat(int rows ,int cols , int type);
这里的type可以是任意的预定义数据类型,比如RGB或者别的多通道数据。这样我们便可以在一个CvMat矩阵上表示丰富多彩的图像了。
2.IplImage
在类型关系上,我们可以说IplImage类型继承自CvMat类型,当然还包括其他的变量将之解析成图像数据。
IplImage类型较之CvMat多了很多参数,比如depth和nChannels。在普通的矩阵类型当中,通常深度和通道数被同时表示,如用32位表示RGB+Alpha.但是,在图像处理中,我们往往将深度与通道数分开处理,这样做是OpenCV对图像表示的一种优化方案。 IplImage的对图像的另一种优化是变量origin----原点。在计算机视觉处理上,一个重要的不便是对原点的定义不清楚,图像来源,编码格式,甚至操作系统都会对原地的选取产生影响。为了弥补这一点,openCV允许用户定义自己的原点设置。取值0表示原点位于图片左上角,1表示左下角。
dataOrder参数定义数据的格式。有IPL_DATA_ORDER_PIXEL和
IPL_DATA_ORDER_PLANE两种取值,前者便是对于像素,不同的通道的数据交叉排列,后者表示所有通道按顺序平行排列。
IplImage类型的所有额外变量都是对“图像”的表示与计算能力的优化。 A.IplImage -> Mat
IplImage* pImg = cvLoadImage(\"lena.jpg\");
Mat img(pImg,0); // 0是不複製影像,也就是pImg與img的data共用同個記憶體位置,header各自有
B.IplImage -> CvMat
法1:CvMat mathdr, *mat = cvGetMat( img, &mathdr );
法2:CvMat *mat = cvCreateMat( img->height, img->width, CV_FC3 ); cvConvert( img, mat ); C.IplImage*-> BYTE*
BYTE* data= img->imageData;
CvMat和IplImage创建时的一个小区别:
1、建立矩阵时,第一个参数为行数,第二个参数为列数。
CvMat* cvCreateMat( int rows, int cols, int type );
2、建立图像时,CvSize第一个参数为宽度,即列数;第二个参数为高度,即行数。这 个和CvMat矩阵正好相反。
IplImage* cvCreateImage(CvSize size, int depth, int channels ); CvSize cvSize( int width, int height );
IplImage内部buffer每行是按4字节对齐的,CvMat没有这个
补充:
A.BYTE*-> IplImage*
img= cvCreateImageHeader(cvSize(width,height),depth,channels); cvSetData(img,data,step);
//首先由cvCreateImageHeader()创建IplImage图像头,制定图像的尺寸,深度和通道数; //然后由cvSetData()根据BYTE*图像数据指针设置IplImage图像头的数据数据,
//其中step指定该IplImage图像每行占的字节数,对于1通道的IPL_DEPTH_8U图像,step可以等于width。
IplImage*图像结构指针转换成byte *
最近在封装opencv中一些标定,视觉方面的函数,接口定义为byte*,需要将byte*与iplImage*相互转换。
其中遇到几个小问题,1)当byte*转成IplImage*时setData()接受图像头,故需要createImageHeader().在上篇cvSetData()中已经说明。
2)在IplImage*转成Byte*时,其实就是取IplImage*中的imageData数据区指针,但是要注意几点:
A:IplImage*指针存放图像有两种方式,由originar变量控制,0-left up为起点,1-left down 为起点。所以要根据origial 处理图像情况。看是否需要对图像进行倒置下。
B:IplImage*存放图像根据读人的格式不同,channel不同。即便是8位图像可能存放成3个通道,所以在转化时获取数据需要注意。 代码贴出来:
////////////////////////////////////////////////////////////////////////// // Name: byte2IplImg
// Function: convert byte* to IplImage format. // Author: liyy
// Data:2011.05.23
//////////////////////////////////////////////////////////////////////////
IplImage * CconvertImgStruct::Byte2IplImg( byte *pImg,int width,int height,int bitCount ) {
if (!pImg ) {
return NULL; }
IplImage * pIplImg
cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,bitCount/BITCHAN) ; long lWidthByte = (width * bitCount+31)/32 *4; cvSetData(pIplImg,pImg,lWidthByte);
return pIplImg; }
////////////////////////////////////////////////////////////////////////// //Name: IplImage2Byte
=
//Function: convert IplImage to byte*
//Author:liyy
//Date: 2011.05.23
//////////////////////////////////////////////////////////////////////////
byte * CconvertImgStruct::IplImage2Byte( IplImage *IplImg ) {
if (!IplImg) {
return NULL;
}
int nHeight = IplImg->height; int nWidth =IplImg->width; int bitCount = IplImg->depth; int nChanel = IplImg->nChannels;
byte *pImg = new byte[nHeight*nWidth*nChanel*sizeof(byte)]; if (IplImg->origin == 0)
{ //from left-down for (int i = 0; i< nHeight;i++) {
for (int j = 0; j< nWidth;j++) {
for (int k =0; k < nChanel;k++) {
//*(pImg+i*nWidth+j*nChanel+k)
*(IplImg->imageData+(nHeight-i-1)*nWidth+j*nChanel+k); pImg[i*nWidth*nChanel+j*nChanel+k]
IplImg->imageData[(nHeight-i-1)*nWidth*nChanel+j*nChanel+k]; } } } } else
{ //from left-up
memcpy(pImg,IplImg->imageData,nHeight*nWidth*nChanel*sizeof(byte)); }
//pImg = (byte *)IplImg->imageData; return pImg; }
= =
}
////////////////////////////////////////////////////////////////////////// //Name: IplImage2Byte
//Function: convert IplImage to byte* //Author:liyy
//Date: 2011.05.23
////////////////////////////////////////////////////////////////////////// byte * CconvertImgStruct::IplImage2Byte( IplImage *IplImg ) {
if (!IplImg) {
return NULL; }
int nHeight = IplImg->height; int nWidth =IplImg->width; int bitCount = IplImg->depth; int nChanel = IplImg->nChannels;
byte *pImg = new byte[nHeight*nWidth*nChanel*sizeof(byte)]; if (IplImg->origin == 0) { //from left-down
for (int i = 0; i< nHeight;i++) {
for (int j = 0; j< nWidth;j++) {
for (int k =0; k < nChanel;k++) {
//*(pImg+i*nWidth+j*nChanel+k)
*(IplImg->imageData+(nHeight-i-1)*nWidth+j*nChanel+k); pImg[i*nWidth*nChanel+j*nChanel+k]
IplImg->imageData[(nHeight-i-1)*nWidth*nChanel+j*nChanel+k]; } } } } else
{ //from left-up
memcpy(pImg,IplImg->imageData,nHeight*nWidth*nChanel*sizeof(byte)); }
= =
//pImg = (byte *)IplImg->imageData; return pImg; }
OpenCV中IplImage图像格式与BYTE图像数据的转换
分类: oencv 2011-04-27 22:33540人阅读评论(1)收藏举报
转自
http://blog.csdn.net/xiaofengsheng/archive/2009/11/16/4814709.aspx OpenCV中IplImage图像格式与BYTE图像数据的转换IplImage* iplImage; BYTE* data;
1 由IplImage*得到BYTE*图像数据:
data = iplImage->imageDataOrigin; //未对齐的原始图像数据 或者
data = iplImage->imageData; //已对齐的图像数据 2 由BYTE*得到IplImage*图像数据
iplImage =
cvCreateImageHeader(cvSize(width,height),depth,channels); cvSetData(iplImage,data,step);
首先由cvCreateImageHeader()创建IplImage图像 头,制定图像的尺寸,深度和通道数;然后由
cvSetData()根据 BYTE*图像数据指针设置IplImage图像头的数据数据,其中step指定该IplImage图像
每行占的字节数,对于1通道的 IPL_DEPTH_8U图像,step可以等于
width。
1,如果是从新创造一个Iplimage,则用IplImage* cvCreateImage( CvSize size, int depth, int channels ),它创建头并分配数据。
注:当不再使用这个新图像时,要调用void
cvReleaseImage( IplImage** image )将它的头和图像数 据释放!
2,如果有图像数据没有为图像头分配存储空间(即,没有为IplImage* 指针分配动态存储空间),则
先调用IplImage* cvCreateImageHeader( CvSize size, int depth, int channels )创建图像头,再
调用void cvSetData( CvArr* arr, void* data, int step )指定图像数据,可以理解为将这个新图
像的数据指针指向了一个已存在的图像数据上,不存在图像数据存储空间的分配操 作。
注:当不再使用这个新图像时,要调用void
cvReleaseImageHeader( IplImage** image )将它的图像 头释放!
3,如果有图像数据也有图像头(用于IplImage为静态分配存储空间的情 况),则先调用IplImage*
cvInitImageHeader( CvSize size, int depth, int channels )更改图像头,
再调用void
cvSetData( CvArr* arr, void* data, int step )指定图像数据。
注:因为这个新图像使用的是其它图像的数据和已有的图像头,所以不能使用 cvReleaseImage将它的
头和图像数据释放,也不能使用cvReleaseData将它的图像数据释 放!
4,如果从已有的一个图像创建,则用IplImage* cvCloneImage( const IplImage* image ),它制作
图像的完整拷贝包括头、ROI和数据。
注:当不再使用这个新图像时,要调用void
cvReleaseImage( IplImage** image )将它的头和图像数 据释放!
图像分割: 概念:
图像分割是将图像划分成若干个互不相交的小区域的过程,所谓小区域是某种意义下具有共同属性的像素的连通集合。
从集合的观点看:它应该是具有如下性质的一种点集,集合R代表整个区域,对R的分割可看作将R分成N个满足以下五个条件的非空子集R1,R2,…,RN:
目的:
无论是图像处理、分析、理解与识别,其基础工作一般都建立在图像分割的基础上; 将图像中有意义的特征或者应用所需要的特征信息提取出来;
图像分割的最终结果是将图像分解成一些具有某种特征的单元,称为图像的基元;
相对于整幅图像来说,这种图像基元更容易被快速处理。
图像分割的特征:
分割出来的各区域对某种性质例如灰度,纹理而言具有相似性,区域内部是连通的的且没有过多小孔。
区域边界是明确的
相邻区域对分割所依据的性质有明显的差异
图像分割的方法:
一、基于像素灰度值的分割方法:阈值(门限)方法
二、基于区域的分割方法:通过直接确定区域间的边界来实现分割的边界方法;
三、基于边缘的分割技术:首先检测边缘像素,再将边缘像素连接起来构成边界形成分割。
图像分割包含的内容:
边缘检测
边缘跟踪:
从图像中一个边缘点出发,然后根据某种判别准则搜索下一个边缘点以此跟踪出目标边界。
阈值分割:
原始图像——f(x,y)
灰度阈值——T
阈值运算得二值图像——g(x,y)
区域分割:
阈值分割法由于没有或很少考虑空间关系,使多阈值选择受到 于区域的分割方法可以弥补这点不足,它利用的是图像的空间性质,该方法认为分割
出来的属于同一区域的像素应具有相似的性质,其概念是相当直观的。
传统的区域分割算法有区域增长法和区域合并法。该类方法在没有先验知识可以利用时,对含有复杂场景
或自然景物等先验知识不足的图像进行分割, 也可以取得较好的性能。但是,空间和时间开销都比较大。
区域生长法主要考虑象素及其空间邻域象素之间的关系
开始时确定一个或多个象素点作为种子,然后按某种相似性准则增
长区域,逐步生成具有某种均匀性的空间区域,将相邻的具有相似性质的象素或区域归并从而逐步增长区域,直至没有可以归并的点或其它小区域为止。
区域内象素的相似性度量可以包括平均灰度值、纹理、颜色等信息。 主要步骤:
选择合适的种子点
确定相似性准则(生长准则) 确定生长停止条件
区域:
条件:如果区域的某些特性不满足一致性准则
开始:从图像的最大区域开始,一般情况下,是从整幅图像开始 注意:
确定准则(一致性准则)
确定方法,即如何区域,使得后的子区域的特性尽可能都满足一致性准则值
图像分割的基本原理:
图像分割是将图像划分成若干个互不相交的小区域的过程,小区域是某种意义下具有共同属性的像素的连通集合。
•如不同目标物体所占的图像区域、前景所占的图像区域等; •连通是指集合中任意两个点之间都存在着完全属于该集合的连通路径;
•对于离散图像而言,连通有4连通和8连通之分。
图像分割有三种不同的途径:
1.是将各像素划归到相应物体或区域的像素聚类方法, 即区域法;
2.是通过直接确定区域间的边界来实现分割的边界方法; 3.是首先检测边缘像素,再将边缘像素连接起来构成边界形成分割。
在图像分割技术中,最常用的是利用阈值化处理进行的图像分割。
在图像的阈值化处理过程中,选用不同的阈值其处理结果差异很大;
阈值过大,会提取多余的部分; 阈值过小,又会丢失所需的部分; 因此,阈值的选取非常重要。
边缘检测和图像分割的联系:
边缘检测后的图像是二值图像,对二值图像可以运用形态学操作来分割目标,
所以边缘检测是图像分割的一个前提。但分割不一定非要用边缘检测。
================================== 图像特征:
•图像特征是指图像中可用作标志的属性,它可以分为统计特征和视觉特征两类。
•图像的统计特征是指一些人为定义的特征,通过变换才能得到,如图像的直方图、 矩、频谱等;
•图像的视觉特征是指人的视觉可直接感受到的自然特征,如区域的亮度、纹理或轮廓等
轮廓提取:
二值图像轮廓提取的算法非常简单,就是掏空内部点: 如果原图像中有一点为黑,且它
的8个邻点都是黑色时,说明该点是内部点,将该点删除(置为白色像素值255)。对
图像中所有像素点执行该操作便可完成图像轮廓的提取。
模板匹配:
模板匹配是指用一个较小的图像,即模板与源图像进行比较,以确定在源图像中是否
存在与该模板相同或相似的区域,若该区域存在, 还可确定其位置并提取该区域。
形状匹配:
形状也是描述图像内容的一个重要特征,利用形状进行匹配需要考虑三个问题。
首先,形状常与目标联系在一起,所以相对于颜色,形状特征可以看作是更高层次的
图像特征。要获得有关目标的形状参数,常常要先对图像进行分割,所以形状特征会
受图像分割效果的影响。其次,目标形状的描述是一个非常复杂的问题,至今还没有
找到能与人的感觉相一致的图像形状的确切数学定义。最后,从不同视角获取的图像中
目标形状可能会有很大差别,为准确进行形状匹配,需要解决平移、尺度、 旋转变换
不变性的问题。
标的形状常常可以用目标的轮廓来表示,而轮廓是由一系列边界点所组成的。一般认为,
在较大尺度下常常能较可靠地消除误检并检测到真正的边界点,但在大尺度下对边界的
定位不易准确。相反,在较小尺度下对真正边界点的定位常比较准确,但在小尺度下
误检的比例会增加。所以,可考虑先在较大尺度下检测出真正的边界点,再在较小尺度
下对真正边界点进行较精确的定位。小波变换和分析作为一种多尺度、多通道分析工具,
比较适合对图像进行多尺度的边界检测。
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- cepb.cn 版权所有 湘ICP备2022005869号-7
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务