1.常用的结构
opencv中定义了一些实用的数据类型,如下:
结构 成员变量 表示的含义
- CvPoint int x,y 图像中的点
- CvPoint2D32f float x,y 二维空间中的点
- CvPoint3D32f float x,y,z 三维空间中的点
- CvSize int width,height 图像的尺寸
- CvRect int x,y,width,height 图像的一个区域
- CvScalar double val[4] RGBA的值
上述结构的第一个的第一个字母小写就是相应的构造函数,由于是用C编写的故实际上是内联函数,比如之前常用的cvSize。通过这些函数就可以很方便的进行一些操作,比如:
#include
#include
#include
#include
#include
#include "cv.h"
#include "highgui.h"
using namespace cv;
using namespace std;
int main( ) {
cvNamedWindow( "Example1", CV_WINDOW_AUTOSIZE );
IplImage* img= cvCreateImage(cvSize( 200, 200 ),IPL_DEPTH_8U,3 );
// cvRectangle矩形函数参数: 图片, 左上角, 右下角, 颜色, 线条粗细(取负值时函数绘制填充了色彩的矩形。), 线条类型,点类型
cvRectangle(img,cvPoint(20,20),cvPoint(100,100),cvScalar(255,0,0),-1);
//cvCircle圆形函数参数为:承载的图像、圆心、半径、颜色、粗细、线型
cvCircle(img,cvPoint(150,150),30,Scalar(0,0,0),1);
cvShowImage("Example1",img);
cvWaitKey(0);
cvReleaseImage( &img );
cvDestroyWindow("Example1");
return 0;
}
2.矩阵和图像类型
1.CvMat矩阵“头”结构
opencv中没有向量结构,但可以用一列矩阵表示;矩阵中的元素也可以不是数字,而是其他类型。CvMat的头结构为:
typedef struct CvMat {
int type;
int step;
int* refcount; // for internal use only
union {
uchar* ptr;
short* s;
int* i;
float* fl;
double* db;
} data;
union {
int rows;
int height;
};
union {
int cols;
int width;
};
} CvMat;
可见里面包含矩阵的行数,列数,数据类型,行数据长度和一些指向数据的指针。
创建CvMat结构有多种方法。
1.使用函数CvMat* cvCreateMat( int rows, int cols, int type )
2.使用CvMat* cvCreateMatHeader( int rows, int cols, int type );创建CvMat结构但不分配内存。
3.CvMat* cvInitMatHeader(
CvMat* mat,
int rows,
int cols,
int type,
void* data = NULL,
int step = CV_AUTOSTEP);为一个已经存在的CvMat结构初始化
4.CvMat cvMat(int rows,int cols,int type,void* data = NULL);与cvInitMatHeader类似但分配内存
5.CvMat* cvCloneMat( const cvMat* mat );依据一个现有矩阵创建新的矩阵
6.void cvReleaseMat( CvMat** mat );清除矩阵
接下来举一个创建矩阵的例子,编译遇到符号冲突问题按Ctrl+F5运行。
#include
#include
#include
#include
#include
#include "cv.h"
using namespace cv;
using namespace std;
int main()
{
CvMat* mat = cvCreateMat( 5, 5, CV_32FC1 );
float vals[25];
for(int i=0;i<25;i++)
{
vals[i]=i;
}
cvInitMatHeader(mat,5,5, CV_32FC1,vals);//用已有的数据Val初始化矩阵
float element_3_2 = CV_MAT_ELEM( *mat, float, 3, 2 );//获取第3行第2列的元素
printf("所创建矩阵的[3,2]=%f\n",element_3_2);
return 0;
}
之后就可进行简单的访问
- 函数cvGetElemType(const CvArr* arr)返回整型常数表示结构
- cvGetDims(const CvArr* arr,int* sizes=NULL)返回维数
- cvGetDimSize(const CvArr* arr,int index)返回index所对应维的大小,对于二维矩阵,第0维表示宽度,第一维表示高。
3.获取矩阵中的数据
在多通道的矩阵中,通道是连续的,如3通道2维表示rgb图像的矩阵中,数据存储形式为rgbrgbrgb....,也就是说指针移动一位进入下一个通道;移动3位进入下一个像素。另外矩阵结构中的step元素表示矩阵行的长度,得到一个指向某点的字节指针,加上step后便到了该点的下一行;而整型和浮点型的矩阵加上step/4,双精度矩阵加上step/8到下一行。
3.1cvPtr*D()函数族
uchar* cvPtr1D(
const CvArr* arr,
int idx0,
int* type = NULL
);
uchar* cvPtr2D(
const CvArr* arr,
int idx0,
int idx1,
int* type = NULL
);
uchar* cvPtr3D(
const CvArr* arr,
int idx0,
int idx1,
int idx2,
int* type = NULL
);
uchar* cvPtrND(
const CvArr* arr,
int* idx,
int* type = NULL,
int create_node = 1,
unsigned* precalc_hashval = NULL
);
3.2 自己计算矩阵的指针
这里要注意多通道矩阵的概念,也就是每个矩阵的元素不是一个点,而是一个c维点列,这就好比一个集合的元素也可以是一个集合。之前讲过多通道矩阵是顺序存储的。
对于一个宽为mat->width,高为mat->height的c通道矩阵,每行的字节长度为mat->step,矩阵头的指针为mat->data.fl,那么a行b列i通道变量的位置为mat->data.fl+a*mat->step/4+b*c+i。注意这里面每行的长度用mat->step计算,而不用mat->width*c,当矩阵不是逐行连续存储的时候这两个可能是不相等的,用后者时出错。下面举一个例子:
#include
#include
#include
#include
#include
#include "cv.h"
using namespace cv;
using namespace std;
int main()
{
CvMat *mat = cvCreateMat(5,5,CV_32FC3);//5*5的3通道矩阵
//赋值
for( int a=0; aheight; a++ ) {
float* ptr = mat->data.fl + a * mat->step/4;
for( int b=0; bwidth; b++ ) {
for(int i=0;i<3;i++){
*(mat->data.fl+a*mat->step/4+b*3+i)=a+b+i;
}
}
}
//显示
for( int a=0; aheight; a++ ) {
printf("\n");
float* ptr = mat->data.fl + a * mat->step/4;
for( int b=0; bwidth*3; b++ ) {
printf("%f ",*ptr);
ptr++;
}
}
return 0;
}