我们经常需要绘制图像或者在已有的图像上方绘制一些图形。为此,OpenCV提供了一系列的函数帮助我们绘制直线、方形和圆形等。
直线
cvLine()是绘图函数中最简单的,只需用Bresenham算法[Bresenham65]画一条线:
void cvLine(
CvArr* array,
CvPoint pt1,
CvPoint pt2,
CvScalar color,
int thickness = 1,
int connectivity = 8
);
cvLine()函数中的第一个属性是CvArr*。在这里,它一般为一个图像类型的指针IplImage*。随后两个CvPoint是一种简单的数据结构,它只包括整型变量x和y。我们可以用CvPoint(int x, int y)函数快速地构造一个CvPoint类型的变量,这样可以方便地把两个整型变量值赋给CvPoint数据结构。
下一个属性是CvScalar类型的颜色变量。CvScalar也是一种数据结构,定义如下所示:
typdef struct {
double val[4];
} CvScalar;
可以看出,这种结构只是四个双精度浮点型变量的集合。在这里,前三个分别代表红,绿,蓝通道;没有用到第四个(它只在适当的时候用于alpha通道)。一个常用的便捷宏指令是CV_RGB(r, g, b),该指令采用三个数字作为参数并将其封装到CvScalar。
接下来的两个属性是可选的。thickness是线的粗细(像素),connectivity被设为反走样模式,默认值为"8连通",这种是较为平滑不会走样的线型。也可以设置为"4连通",这样的话,斜线会产生重叠以致看上去过于粗重,不过画起来速度要快得多。
cvRectangle()和cvLine()几乎同样便捷。cvRectangle()用于画矩形。除了没有connectivity参数,它和cvLine()的其他参数都是一样的。因为由此产生的矩形总是平行与X和Y轴。利用cvRectangle(),我们只需给出两个对顶点,OpenCV便于画出一个矩形。
矩形
void cvRectangle(
CvArr* array,
CvPoint pt1,
CvPoint pt2,
CvScalar color,
int thickness = 1
);
圆形和椭圆
画圆同样简单,其参数与前相同。
- void cvCircle (
- CvArr* array,
- CvPoint center,
- int radius,
- CvScalar color,
- int thickness = 1,
- int connectivity = 8
- );
对圆形和矩阵等很多封闭图形来说,thickness参数也可以设置为CV_FILL,其值是-1;其结果是使用与边一样的颜色填充圆内部。
椭圆函数比cvCircle()略微复杂一些:
- void cvEllipse(
- CvArr* img,
- CvPoint center,
- CvSize axes,
- double angle,
- double start_angle,
- double end_angle,
- CvScalar color,
- int thickness = 1,
- int line_type = 8
- );
【79】
这里,主要的新成员是axes属性,其类型为CvSize。CvSize函数与CvPoint和CvScalar非常相似;这是一个仅包含宽度和高度的简单结构。同CvPoint和CvScalar一样,CvSize也有一个简单的构造函数cvSize(int height, int width),在需要的时候返回一个CvSize数据。在这种情况下,height和width参数分别代表椭圆的长短半轴长。
angle是指偏离主轴的角度,从X轴算起,逆时针方向为正。同样,start_angle和end_angle表示弧线开始和结束位置的角度。因此,一个完整的椭圆必须分别将这两个值分别设为0°和360°。
外接矩形
使用外接矩形是描述椭圆绘制的另一种方法:
- void cvEllipseBox(
- CvArr* img,
- CvBox2D box,
- CvScalar color,
- int thickness = 1,
- int line_type = 8,
- int shift = 0
- );
这里用到OpenCV的另一个结构CvBox2D:
- typdef struct {
- CvPoint2D32f center;
- CvSize2D32f size;
- float angle;
- } CvBox2D;
CvPoint2D32f是CvPoint的浮点形式,同时CvSizet2D32f也是CvSize的浮点形式。这些,连同倾斜角度,可以有效地描述椭圆的外接矩形
最后,我们有一系列绘制多边形的函数。
- void cvFillPoly(
- CvArr* img,
- CvPoint** pts,
- int* npts,
- int contours,
- CvScalar color,
- int line_type = 8
- );
- void cvFillConvexPoly(
- CvArr* img,
- CvPoint* pts,
- int npts,
- CvScalar color,
- int line_type = 8
- );
- void cvPolyLine(
- CvArr* img,
- CvPoint** pts,
- int* npts,
- int contours,
- int is_closed,
- CvScalar color,
- int thickness = 1,
- int line_type = 8
- );
【79~80】
上述三种方法依据同一思路又略有不同,其主要区别是如何描述点。
在cvFillPoly()中,点是由CvPoint数组提供的。它允许cvFillPoly()在一次调用中绘制多个多边形。同样地,npts是由记数点构成的数组,与多边形对应。如果把变量is_closed设为true,那么下一个多边形的第一个线段就会从上一多边形最后一点开始。cvFillPoly()很稳定,可以处理自相交多边形,有孔的多边形等复杂问题。然而不幸的是,函数运行起来相对缓慢。
cvFillConvexPoly()和cvFillPoly()类似。不同的是,它一次只能画一个多边形,而且只能画凸多边形 。好处是,cvFillConvexPoly()运行得更快。
第三个cvPolyLine(),其参数与cvFillPoly()相同,但因为只需画出多边形的边,不需处理相交情况。因此,这种函数运行速度远远超过cvFillPoly()。