OpenCV数据结构和绘图函数
1. Mat数据结构详解
1.1. Mat结构组成和适用方法
l Mat由两个数据部分组成 : 即矩阵头 + 指向矩阵的指针。
矩阵头 = 矩阵尺寸 + 存储方法 + 储存地址等
OpenCV 每个Mat对象有属于自己的信息头,但是共享同一个矩阵,它通过矩阵指针指向同一个矩阵的地址实现。
Mat A,C; //仅创建信息头部分
A = imread(“1.jpg”,CV_LOAD_IMAGE_COLOR); //这里为就诊开辟内存空间
Mat B(A); //拷贝构造函数
C = A; // 复制运算符
l 创建包含边界信息的信息头的方法:
Mat D(A,Rect(10,10,100,100)); //用矩形界定
Mat E(Range:all(),Range(1,3));//用行和列来界定
l Mat 的引用计数概念:
每当复制一个Mat对象的信息头时,增加引用计数,
每当一个信息头被释放的时候,减小引用计数。
l 通过copyTo或clone复制矩阵
Mat F = A.clone();
Mat G;
A.copyTo(G);
l 获取图像的长和宽
Ip1Image* img = cvLoadImage(“1,jpg”,1);
Mat mtx(img);
img.width(),img.Heihgt()
1.2. 像素值的存储方法
存储像素需要指定颜色空间和数据类型。
颜色空间概念:针对一个给定的颜色,如何组合颜色元素以对其编码。
如灰度级空间,只处理黑色和白色。
彩色的颜色空间: RGB + 透明颜色 四个元素。
颜色系统种类:
1) RGB 显示设备所采用
2) HSV和HLS把颜色分解成色调、饱和度和亮度透明度
3) YCrCb在JPEG图像格式中广泛使用
4) ClE L*a*b 是一种感知上均匀的颜色空间,他适合用来度量两个颜色之间的距离。
1.3. 创建Mat对象的方法
1) 使用Mat 构造函数
Mat M(2,2,CV_8UC3,Scalar(0,0.255));
参数1 | 参数2 | 参数3 | 参数4 |
行 | 列 | 数据类型 | 通道数 |
数据类型结构:
CV | 位数 | 带符号与否 | 类型前缀 | C | 通道数 |
2) C\C++中通过构造函数进行初始化
Int sz[3] = {2,2,2};
Mat L(3,sz,CV_8UC,Scalar::all(0));
3) 为已存在的Ip1Image指针创建信息头
Ip1Image* img = cvLoadImage(“1,jpg”,1);
Mat mtx(img);
4) 利用Create()函数
M.creat(4,4,CV_8UC(2));
Cout <<”M=”<<” ”<<M<<endl;
1.4. OpenCV格式化输出
1.5. 常用数据结构输出
l 定义输出二维点
Point2fp(6, 2);
cout<< "【?2维?点Ì?】?p = " << p << ";\n" << endl;
l 定义输出三维点
Point3fp3f(8, 2, 0);
cout<< "【?3维?点Ì?】?p3f = " << p3f << ";\n" << endl;
l 定义输出基于Mat的std::vector
vector<float>v;
v.push_back(3);
v.push_back(5);
v.push_back(7);
cout<< "【?基¨´于®¨²Mat的Ì?vector】?shortvec = " << Mat(v) <<";\n"<<endl;
l 定义输出Mat的std::vector
vector<Point2f>points(20);
for(size_t i = 0; i < points.size(); ++i)
points[i]= Point2f((float)(i * 5), (float)(i % 7));
cout<< "【?二t维?点Ì?向¨°量¢?】?points = " << points<<";";
2. IplImage 数据结构详解
2.1. IplImage与Mat的关系
OpenCV最初是C语言编写的一个图形库,其中IplImage是表示一个图像的结构体,也是从OpenCV1.0到目前最为重要的一个结构;
Mat是后来OpenCV封装的一个C++类,用来表示一个图像,和IplImage表示基本一致,但是Mat还添加了一些图像函数;
2.2. IplImage与Mat 创建图像数据的不同
2.2.1. IplImage创建图像数据
IplImage ,通过以下三个函数之一创建:
/*Allocates and initializes IplImage header */
CVAPI(IplImage*) cvCreateImageHeader( CvSize size, int depth, intchannels );
/*Inializes IplImage header */
CVAPI(IplImage*)cvInitImageHeader( IplImage* image, CvSize size, intdepth,
int channels, intorigin CV_DEFAULT(0),
int align CV_DEFAULT(4));
/*Creates IPL image (header and data) */
CVAPI(IplImage*) cvCreateImage( CvSize size, int depth, intchannels );
2.2.2. Mat 创建图像数据
cv::Mat,直接可以通过构造函数Mat(int _rows, int _cols, int _type, void*_data, size_t _step=AUTO_STEP); 直接创建;
示例:
cv::Mat * pMat = new cv::Mat( 288, 352, CV_8UC3, imagebufdata );
IplImage IplImagetmp = IplImage(*pMat);
注意:前两个参数是图像的height和width,不是width和height;
2.2.3. IplImage和Mat 创建图像的比较
创建内存数据图像,直接通过 cv::Mat类比较简单,然后可以通过Mat获取IplImage,通过cvCreateImage等函数创建内存图像,比较麻烦,而且创建后,还要通过cvReleaseImage等函数释放内存,所以这里建议用cv::Mat创建;
2.3. IplImage和Mat的互相转换
l IplImage 转 Mat:
// extern IplImage * plpliamge; //假设 IplImage 已经创建;
Mat * pmatImage = new Mat( IplImage,0 ): //第二个参数表示不进行像素数据copy;
l Mat 转 IplImage:
//extern Mat matImage; //假设已经创建cv:Mat;
IplImage limage = IplImage ( matImage );//不进行数据copy;
通常情况对于图像的读取,IplImage 通过 cvLoadImage, cv:Mat通过 cv::imread;
2.4. IplImage 结构体详解 – 源代码
typedef struct _IplImage
{
int nSize; /*sizeof(IplImage) */
int ID; /*version (=0)*/
int nChannels; /* Most ofOpenCV functions support 1,2,3 or 4 channels */
int alphaChannel; /* Ignored byOpenCV */
int depth; /* Pixeldepth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,
IPL_DEPTH_32S,IPL_DEPTH_32F and IPL_DEPTH_64F are supported. */
charcolorModel[4]; /* Ignored by OpenCV */
charchannelSeq[4]; /* ditto */
int dataOrder; /* 0 -interleaved color channels, 1 - separate color channels.
cvCreateImage can only createinterleaved images */
int origin; /* 0 -top-left origin,
1 - bottom-leftorigin (Windows bitmaps style). */
int align; /*Alignment of image rows (4 or 8).
OpenCV ignoresit and uses widthStep instead. */
int width; /* Imagewidth in pixels. */
int height; /* Imageheight in pixels. */
struct_IplROI *roi; /*Image ROI. If NULL, the whole image is selected. */
struct_IplImage *maskROI; /* Must be NULL. */
void *imageId; /*" " */
struct_IplTileInfo *tileInfo; /* " " */
int imageSize; /* Imagedata size in bytes
(==image->height*image->widthStep
in case ofinterleaved data)*/
char*imageData; /* Pointer toaligned image data. */
int widthStep; /* Size ofaligned image row in bytes. */
int BorderMode[4]; /* Ignored byOpenCV. */
int BorderConst[4]; /* Ditto. */
char*imageDataOrigin; /* Pointer to very origin of image data
(not necessarilyaligned) -
needed forcorrect deallocation */
}
IplImage;
3. OpenCV常用类和数据结构
3.1. Point类 – 点
Point point;
Point.x = 10;
Point.y = 8;
或者 Point point = point(10,8);
另外Point_<int> ;Point2i; Point 互相等价,Point_<float>; Point2f
3.2. Scalar类 – 颜色
Scalar(a,b,c) ; abc 即RGB; 用于传递像素值,还有第四个元素是透明,可以不写出来。
3.3. Size 类 – 尺寸
Size_类模板提供了一些构造函数,具体可以查看D:\Program Files (x86)\opencv\sources\modules\core\include\opencv2\core.cpp;
template<typename_Tp> class Size_
{
public:
typedef _Tpvalue_type;
//! variousconstructors
Size_();
Size_(_Tp _width, _Tp _height);
Size_(constSize_& sz);
Size_(constCvSize& sz);
Size_(constCvSize2D32f& sz);
Size_(constPoint_<_Tp>& pt);
Size_& operator= (const Size_& sz);
//! the area(width*height)
_Tp area() const;
//! conversion ofanother data type.
template<typename _Tp2> operatorSize_<_Tp2>() const;
//! conversion tothe old-style OpenCV types
operatorCvSize() const;
operatorCvSize2D32f() const;
_Tp width, height; //the width and the height
};
最常用的是 Size_(_Tp _width, _Tp _height);
定义模板类型的宽度和高度。
3.4. Rect 类 – 矩形
Rect_类,成员变量x、y、width、height,分别为左上角点的坐标和矩形的宽和高。常用的成员函数有Size()返回值为一个Size,area()返回矩形的面积,contains(Point)用来判断点是否在矩形内,inside(Rect)函数判断矩形是否在该矩形内,tl()返回左上角点坐标,br()返回右下角点坐标。值得注意的是,如果想求两个矩形的交集,并集,可以用如下格式
l 求两个矩形的交集和并集
Rect rect = rect1 & rect2;
Rect rect = rect1 | rect2;
l 矩形的平移和缩放
Rect RectShift = rect1 + point;
Rect RectScale = rect1 + size;
l 返回矩形的面积
AreaRect = area();
l 判断点是否在矩形内
bPointInRect = Contains(Point);
l 判断矩形是否在矩形内
bRectInRect = Inside(Rect);
3.5. CvtColor 类 – 颜色空间
CvtColor() 是OpenCV里颜色空间转换函数,实现RGB、HSV HIS 空间的转换
也可转化为灰度图像。
函数原型:
void cv::cvtColor( InputArray _src, OutputArray _dst,int code, intdcn )
参数1 | 输入图像 |
参数2 | 输出图像 |
参数3 | 颜色空间转换标识符 |
参数4 | 目标图像通道数 |
颜色空间的转换标识符类型
enum
{
CV_BGR2BGRA =0,
CV_RGB2RGBA =CV_BGR2BGRA,
CV_BGRA2BGR =1,
CV_RGBA2RGB =CV_BGRA2BGR,
CV_BGR2RGBA =2,
CV_RGB2BGRA =CV_BGR2RGBA,
CV_RGBA2BGR =3,
CV_BGRA2RGB =CV_RGBA2BGR,
CV_BGR2RGB =4,
CV_RGB2BGR =CV_BGR2RGB,
CV_BGRA2RGBA =5,
CV_RGBA2BGRA =CV_BGRA2RGBA,
CV_BGR2GRAY =6,
CV_RGB2GRAY =7,
CV_GRAY2BGR =8,
CV_GRAY2RGB =CV_GRAY2BGR,
CV_GRAY2BGRA =9,
CV_GRAY2RGBA =CV_GRAY2BGRA,
CV_BGRA2GRAY =10,
CV_RGBA2GRAY =11,
…
CV_RGBA2YUV_I420 = 129,
CV_BGRA2YUV_I420 = 130,
CV_RGBA2YUV_IYUV = CV_RGBA2YUV_I420,
CV_BGRA2YUV_IYUV = CV_BGRA2YUV_I420,
CV_RGB2YUV_YV12 = 131,
CV_BGR2YUV_YV12 = 132,
CV_RGBA2YUV_YV12 = 133,
CV_BGRA2YUV_YV12 = 134,
CV_COLORCVT_MAX = 135
};
3.6. 一些常用的知识点
Matx类 | 轻量级的Mat 使用前规定好大小,如Mat23f 即是定义一个2*3的float型的Mat | |
Vec类 | Matx 的派生类,一维的Matx | |
Range类 | Range::all() 是matlab符号,Range(a,b) 是Matlab中的a:b | |
防溢出函数 | AlignPtr(), alignSize(), allocate(), deallocate(), fastMalloc(), fastFree() | |
数学库函数 | FastAtan2 | 计算向量角度的函数 |
cubeRoot | 计算立方根的函数 | |
cvCeil | 向上取整函数 | |
cvFloor | 向下取整函数 | |
cvRound | 四舍五入函数 | |
cvIsInf | MatLab函数,判断自变量是否无求大 | |
cvIsNaN | MatLab函数,判断自变量是否不是一个数 | |
显示文字的函数 | getTextSize, cvInitFont, putText | |
作图函数 | Circle, clipLine,ellipse,ellipse2Poly,line,rectangle,polylines,类LineIterator | |
填充函数 | fillCibvexPoly, fillPoly | |
随机数 | RNG() |
4. OpenCV基本图形绘制
4.1. 基本的绘图函数
绘制直线 | void line( Mat& img, Point pt1, Point pt2, const int thickness, int line_type, int |
绘制椭圆 | void double angle, double start_angle, double const Scalar& color, int thickness, int line_type, int |
绘制矩形 | void const Scalar& color, int int lineType, int |
绘制圆形 | void circle( Mat& img, Point center, int const Scalar& color, int thickness, int line_type, int
|
绘制填充 | void fillPoly( Mat& img, const Point** pts, const int* npts, int const Scalar& color, int int |
4.2. DrawEillpse函数的写法
OpenCV 官方例子:
绘制不同角度,尺寸相同的椭圆。
void DrawEllipse( Mat img, doubleangle )
{
intthickness = 2;
intlineType = 8;
ellipse( img,
Point( WINDOW_WIDTH/2,WINDOW_WIDTH/2 ),//中心点
Size( WINDOW_WIDTH/4,WINDOW_WIDTH/16 ),//位于矩形范围内
angle,//椭圆旋转角度
0, //画椭圆的起始弧度
360,// 椭圆的终止弧度
Scalar( 255, 129, 0 ),// 图形的颜色BGR,此为蓝色
thickness,// 线宽为2
lineType );// 线型为8 即8联通线型
}
4.3. DrawFilledCircle的写法
实现实心圆绘制:
void DrawFilledCircle( Mat img, Point center )
{
intthickness = -1;
intlineType = 8;
circle( img,
center, //圆心
WINDOW_WIDTH/32, //圆的半径
Scalar( 0, 0, 255 ), //图形的颜色BGR,此为红色
thickness, //线宽为2
lineType ); //线型为8 即8联通线型
}
4.4. DrawPolygon的写法
实现凹多边形的绘制:
void DrawPolygon( Mat img )
{
intlineType = 8;
//创ä¡ä建¡§一°?些?点Ì?
Point rookPoints[1][20];
rookPoints[0][0] = Point( WINDOW_WIDTH/4, 7*WINDOW_WIDTH/8);
rookPoints[0][1] = Point( 3*WINDOW_WIDTH/4, 7*WINDOW_WIDTH/8 );
rookPoints[0][2] = Point( 3*WINDOW_WIDTH/4, 13*WINDOW_WIDTH/16 );
rookPoints[0][3] = Point( 11*WINDOW_WIDTH/16,13*WINDOW_WIDTH/16 );
rookPoints[0][4] = Point( 19*WINDOW_WIDTH/32, 3*WINDOW_WIDTH/8 );
rookPoints[0][5] = Point( 3*WINDOW_WIDTH/4, 3*WINDOW_WIDTH/8 );
rookPoints[0][6] = Point( 3*WINDOW_WIDTH/4, WINDOW_WIDTH/8 );
rookPoints[0][7] = Point( 26*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][8] = Point( 26*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][9] = Point( 22*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][10] = Point(22*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][11] = Point(18*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][12] = Point(18*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][13] = Point(14*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][14] = Point( 14*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][15] = Point( WINDOW_WIDTH/4, WINDOW_WIDTH/8 );
rookPoints[0][16] = Point( WINDOW_WIDTH/4, 3*WINDOW_WIDTH/8 );
rookPoints[0][17] = Point(13*WINDOW_WIDTH/32, 3*WINDOW_WIDTH/8 );
rookPoints[0][18] = Point( 5*WINDOW_WIDTH/16, 13*WINDOW_WIDTH/16 );
rookPoints[0][19] = Point( WINDOW_WIDTH/4, 13*WINDOW_WIDTH/16 );
constPoint* ppt[1] = { rookPoints[0] };
intnpt[] = { 20 };
fillPoly( img,
ppt, //多边形的顶点集
npt, //多边形的顶点数目
1, // 多边形的数量仅为1
Scalar( 255, 255, 255 ), //图形的颜色BGR,此为白色
lineType ); //线型为8 即8联通线型
}
4.5. DrawLine的写法
实现了线的绘制:
void DrawLine( Mat img, Point start, Point end )
{
intthickness = 2;
intlineType = 8;
line( img,
start,
end,
Scalar( 0, 0, 0 ), // 图形的颜色BGR,此为黑色
thickness,线宽为2
lineType ); //线型为8 即8联通线型
}