绘图是OpenCV经常使用的一个地方,很多时候我们需要绘制图像或者在已有的图像上方绘制一些图像。

1. 绘制直线

函数原型:

void cvLine(
  CvArr*    array,
  CvPoint    pt1,
  CvPoint    pt2,
  CvScalar    color,
  int        thickness = 1,
  int        connectivity = 8
);

第一个参数 一般为一个图像类型的指针IplImage*。

第二个和第三个参数分别为直线的起点和终点,是CvPoint类型的,我们可以使用cvPoint(int x, int y)构造函数很方便的构造一个CvPoint类型的变量。

第四个参数是一个CvScalar类型的颜色变量,其结构前面已经介绍过,是一个包含四个双精度浮点型变量的集合。在这里。前三个分别代表红、绿、蓝通道(但其实因为RGB在内存里面的存储顺序是BGRA BGRA,所以当使用CVScalar类型表示颜色时,其实四个分量分别代表B、G、R、A。如果想按照RGBA的顺序,可以使用后面介绍的宏CV_RGB构造CvScalar类型,而不是cvScalar。关于这一点,最后面的例子中也会有体现);没有用到第四个(它只在适当的时候用于alpha通道)。一个常用的便捷宏指令是CV_RGB(r, g, b),该指令采用三个数字作为参数并将其封装到CvScalar。

最后两个参数是可选的,因为都有默认值。thickness是线的粗细(像素)。connectivity被设为反走样模式,默认值为“八连通”,这种是较为平滑不会走样的线型。也可以设置为“4连通”,这样的话,斜线会产生重叠以致看上去过于粗重,不过画起来速度很快。

2. 绘制矩形

函数原型:

void cvRectangle(
  CvArr*    array,
  CvPoint    pt1,
  CvPoint    pt2,
  CvScalar    color,
  int        thickness = 1
);

从函数原型就可以看出,这个函数和cvLine( )除了最后一个参数外,其他都一样。的确是,因为这个函数画的矩形总是平行于X和Y轴。利用这个函数画矩形,只需要给出两个对顶点就可以。

3. 绘制圆形和椭圆

函数原型:

void cvCircle (
  CvArr*    array,
  CvPoint    center,
  int        radius,
  CvScalar    color,
  int        thickness = 1,
  int        connectivity = 8
);

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
);

// 使用外接矩形绘制椭圆
void cvEllipseBox(
  CvArr*    img,
  CvBox2D    box,
  CvScalar    color,
  int        thickness = 1,
  int         line_type = 8,
  int        shift = 0
);

画圆也很简单,参数和前面介绍的基本相同,这里就不多介绍了。对于圆形和矩阵等很多封闭图形来说,thickness参数也可以设置为CV_FILL,其值是-1,;其结果是使用与边一样的颜色填充封闭空间。

椭圆函数比cvCircle( )略复杂一点。主要的新成员是axes属性,其类型为CvSize,其结构前面已经介绍过,是一个包含宽度和高度的简单结构。同样,可以利用其构造函数cvSize( )得到一个CvSize结构。在这种情况下,height和width参数分别代表椭圆的长短半轴长。  angle是指偏离主轴的角度,从X轴算起,逆时针方向为正。同样,start_angle和end_angle表示弧线开始和结束位置的角度。因此,一个完整的椭圆必须分别将这两个值分别设为0°和360°。

除了cvEllipse( )函数外,还可以使用外接矩形的方法绘制椭圆,函数是cvEllipseBox( )。该函数用到一个CvBox2D结构:

typedef struct {
  CvPoint2D32f    center,
  CvSize2D32f    size,
  float        angle
} CvBox2D;

4. 绘制多边形

绘制多边形有多个函数:

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_tyoe = 8
);

void cvPolyLine (
  CvArr*    img,
  CvPoint**    pts,
  int*        npts,
  int        contours,
  int        is_closed,
  CvScalar    color,
  int        thickness = 1,
  int        line_type = 8
);

这三个函数都可以绘制多边形,思路也基本相同,主要区别是如何描述点:

在cvFillPolly( )中,点是由CvPoint数组提供的。它允许cvFillPoly( )在一次调用中绘制多个多边形。同样的,npts是由计数点构成的数组,与多边形对应。如果把变量is_closed设为ture,那么下一个多边形的第一个线段就会从上一多边形最后一个点开始。cvFillPoly很稳定,可以处理自相交多边形,有孔的多边形等复杂问题。然而缺点是函数运行起来相对缓慢。

cvFillConvexPoly( )和cvFillPoly( )类似。不同的是,它一次只能画一个多边形,而且只能画凸多边形。优点是函数运行速度快。

第三个cvPolyLine( ),七参数与cvFillPoly( )基本相同,但因为只需画出多边形的边,不需处理相交情况。因此,函数运行速度远远超过cvFillPoly( )。

5. 绘制文字

OpenCV有一个主要的函数,叫cvPutText( ),这个函数可以在图像上输出一些文本。函数原型:

void cvPutText (
  CvArr*    img,
  const        text,
  CvPoint    origin,
  const CvFont*    font,
  CvScalar    color
);

参数text所指向的文本将打印到图像上。

参数origin指定文本框左下角位置。

参数color指定文本颜色。

要获取CvFont*指针需要调用函数cvInitFont( )函数。函数原型:

void cvInitFont (
  CvFont*    font,
  int        font_face,
  double    hscale,
  double    vscale,
  double    shear = 0,
  int        thickness = 1,
  int        line_type = 8
);

该函数采用一组参数配置一些用于屏幕输出的基本特定字体。为了建立一个可以传值给cvPutText( )的cvFont,首先必须声明一个CvFont变量,然后把它传递给cvInitFont( )。

font_face是选择字体,且该标志可以和CV_FONT_ITALIC(字体标志)组合使用(使用与或)。以下是全部可用的字体:

标志名称 描述
CV_FONT_HERSHEY_SIMPLEX 正常尺寸的sanserif字体
CV_FONT_HERSHEY_PLAIN 小尺寸的sanserif字体
CV_FONT_HERSHEY_DUPLEX 正常尺寸的sanserif字体,但比CV_FONT_HERSHEY_SIMPLEX 复杂
CV_FONT_HERSHEY_COMPLEX 正常尺寸serif,比CV_FONT_HERSHEY_DUPLEX更复杂
CV_FONT_HERSHEY_TRIPLEX 正常尺寸serif,比CV_FONT_HERSHEY_COMPLEX更复杂
CV_FONT_HERSHEY_COMPLEX_SMALL 小尺寸的CV_FONT_HERSHEY_COMPLEX
CV_FONT_HERSHEY_SCRIPT_SIMPLEX 手写风格
CV_FONT_HERSHEY_SCRIPT_COMPLEX 比CV_FONT_HERSHEY_SCRIPT_SIMPLEX更复杂

hscale和vscale只能设定为1.0或0.5,。字体渲染时选择全高或半高(宽度同比缩放),绘制效果与指定字体的基本定义有关。

参数shear创建斜体字,如果设置为0.0,字体不倾斜。当设置为1.0时,字体倾斜范围接近45°。

其他两个参数与以前相同。

下面用一个例子来说明前面介绍的知识:

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <stdio.h>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    IplImage *image = cvCreateImage(cvSize(800, 600), 8, 3);

    // Draw Line
    cvLine(image, cvPoint(10, 10), cvPoint(500, 20),
            cvScalar(255), 2, 8, 1);

    // Draw Circle
    cvCircle(image, cvPoint(100, 100), 50, cvScalar(0, 255, 0), 2, 8, 0);

    // Draw Ellipse
    cvEllipse(image, cvPoint(400, 150),
        cvSize(100, 150), 45, 0, 360, cvScalar(0, 0, 255), 2);

    cvEllipse(image, cvPoint(600, 150),
        cvSize(100, 150), 0, 0, 360, CV_RGB(0, 0, 255), 2);

    // Draw Text
    CvFont  font1, font2, font3, font4, font5, font6, font7, font8;
    char* text = "Time Track";
    cvInitFont(&font1, CV_FONT_HERSHEY_COMPLEX, 1, 1, 0);
    cvPutText(image, text, cvPoint(100, 200), &font1, CV_RGB(0, 0, 0));

    cvInitFont(&font2, CV_FONT_HERSHEY_PLAIN, 1, 0.5, 0.2);
    cvPutText(image, text, cvPoint(100, 250), &font2, CV_RGB(0, 0, 0));

    cvInitFont(&font3, CV_FONT_HERSHEY_DUPLEX, 0.5, 1, 0.4);
    cvPutText(image, text, cvPoint(100, 300), &font3, CV_RGB(0, 0, 0));

    cvInitFont(&font4, CV_FONT_HERSHEY_COMPLEX, 0.5, 1, 0.6);
    cvPutText(image, text, cvPoint(100, 350), &font4, CV_RGB(0, 0, 0));

    cvInitFont(&font5, CV_FONT_HERSHEY_TRIPLEX | CV_FONT_ITALIC, 1, 1, 0.8);
    cvPutText(image, text, cvPoint(100, 400), &font5, CV_RGB(0, 0, 0));

    cvInitFont(&font6, CV_FONT_HERSHEY_COMPLEX_SMALL, 1, 1, 1);
    cvPutText(image, text, cvPoint(100, 450), &font6, CV_RGB(0, 0, 0));

    cvInitFont(&font7, CV_FONT_HERSHEY_SCRIPT_SIMPLEX, 1, 1, 2);
    cvPutText(image, text, cvPoint(100, 500), &font7, CV_RGB(0, 0, 0));

    cvInitFont(&font8, CV_FONT_HERSHEY_SCRIPT_COMPLEX, 1, 1, 3);
    cvPutText(image, text, cvPoint(200, 550), &font8, CV_RGB(0, 0, 0));

    cvNamedWindow("Display");
    cvShowImage("Display", image);

    cvWaitKey();
    return 0;
}