opencv常用绘制方法

  • 前言
  • 1.直线line
    • line的函数原型如下
    • 使用方法
  • 2.箭头arrowedLine
    • arrowedLine的函数原型如下
    • 使用方法
  • 3.矩形rectangle、
    • rectangle的函数原型如下
    • 使用方法
  • 4.圆circle
    • circle的函数原型如下
    • 使用方法
  • 5.椭圆ellipse
    • ellipse的函数原型如下
    • 使用方法
  • 6.多边形polylines
    • polylines的函数原型如下
    • 使用方法
  • 7.文字putText
    • putText的函数原型如下
    • 使用方法
  • 8.不常见功能绘制标记drawMarker
    • drawMarker的函数原型如下
    • 支持的类型如下
    • 使用方法
  • 9.不常用方法,填充凸多边形内部fillConvexPoly
    • fillConvexPoly的函数原型如下
    • 使用方法
  • 10.不常用方法,填充复杂多边形内部fillPoly
    • fillPoly的函数原型如下
    • 使用方法
  • 11.不常用方法,绘制轮廓drawContours
    • drawContours的函数原型如下
    • findContours
    • 绘制类型mode
    • 使用方法

前言

导出函数在文件modules\imgproc\include\opencv2\imgproc.hpp中
opencv绘制使用的参数都是基于opencv的类型的
一般第一个参数是cv::Mat 类型的,表示需要处理的图像的像素矩阵
绘制的像素点使用cv::Point
绘制的颜色是cv::Scalar,这个颜色是BGRA的格式
绘制的线宽一般是int的static const int MAX_THICKNESS = 32767;最大线宽是32767,一般用不上
比较常用的参数,线宽,线型,放缩倍率一般都有默认值,线宽默认是1代表单位还需要研究,线型默认是8,放缩倍率默认是0
线型定义如下,其中LINE_AA为边缘像素采用高斯滤波,图像锯齿会稍微好一点

/** types of line
@ingroup imgproc_draw
*/
enum LineTypes {FILLED  = -1,LINE_4  = 4, //!< 4-connected lineLINE_8  = 8, //!< 8-connected lineLINE_AA = 16 //!< antialiased line
};

shift 放缩倍率的值表示缩小到2的几次方,是使用移位操作实现的,所以这个参数实际是一个缩小参数这个缩小的中心点是0,0。因为这个shift是对绘制的点集point直接进行放缩的,所以很不好控制,一般不用这个参数进行放缩。

1.直线line

line的函数原型如下

函数的五个参数分别是图像的mat矩阵,起始点,结束点,颜色,线宽,线型,和放缩倍率(一般不用)

void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar& color,int thickness, int line_type, int shift )
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( line_type == CV_AA && img.depth() != CV_8U )line_type = 8;CV_Assert( 0 < thickness && thickness <= MAX_THICKNESS );CV_Assert( 0 <= shift && shift <= XY_SHIFT );double buf[4];scalarToRawData( color, buf, img.type(), 0 );ThickLine( img, pt1, pt2, buf, thickness, line_type, 3, shift );
}

使用方法

line(img,(0,0),(100,100),(255,0,0),2)

后面的line_type和shift 一般使用默认值就可以了。

2.箭头arrowedLine

arrowedLine的函数原型如下

相比于划线,只是多了一个参数tipLength,这个参数默认值位0.1代表单位还需要研究,基本这个单位返回绘制的箭头就可见了,具体需求自己可以调节。

void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,int thickness, int line_type, int shift, double tipLength)
{CV_INSTRUMENT_REGION();const double tipSize = norm(pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrowline(img, pt1, pt2, color, thickness, line_type, shift);const double angle = atan2( (double) pt1.y - pt2.y, (double) pt1.x - pt2.x );Point p(cvRound(pt2.x + tipSize * cos(angle + CV_PI / 4)),cvRound(pt2.y + tipSize * sin(angle + CV_PI / 4)));line(img, p, pt2, color, thickness, line_type, shift);p.x = cvRound(pt2.x + tipSize * cos(angle - CV_PI / 4));p.y = cvRound(pt2.y + tipSize * sin(angle - CV_PI / 4));line(img, p, pt2, color, thickness, line_type, shift);
}

使用方法

arrowedLine(img, Point(0, 0), Point(100, 100), Scalar(255, 0, 0), 1, 8, 0, 0.1);

基本后面的参数都是用的默认值,完全可以这样写

arrowedLine(img, Point(0, 0), Point(100, 100), Scalar(255, 0, 0));

但是一旦需要定制箭头大小,就需要把所有参数都写上

3.矩形rectangle、

rectangle的函数原型如下

可以看到rectangle函数有两个定义,第二个定义只是将两个point用rect代替了,并且最后还是调用第一个函数执行的绘制,所以这里只需要分析第一个函数

void rectangle( InputOutputArray _img, Point pt1, Point pt2,const Scalar& color, int thickness,int lineType, int shift )
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( lineType == CV_AA && img.depth() != CV_8U )lineType = 8;CV_Assert( thickness <= MAX_THICKNESS );CV_Assert( 0 <= shift && shift <= XY_SHIFT );double buf[4];scalarToRawData(color, buf, img.type(), 0);Point2l pt[4];pt[0] = pt1;pt[1].x = pt2.x;pt[1].y = pt1.y;pt[2] = pt2;pt[3].x = pt1.x;pt[3].y = pt2.y;if( thickness >= 0 )PolyLine( img, pt, 4, true, buf, thickness, lineType, shift );elseFillConvexPoly( img, pt, 4, buf, lineType, shift );
}void rectangle( InputOutputArray img, Rect rec,const Scalar& color, int thickness,int lineType, int shift )
{CV_INSTRUMENT_REGION();if( !rec.empty() )rectangle( img, rec.tl(), rec.br() - Point(1<<shift,1<<shift),color, thickness, lineType, shift );
}

使用方法

rectangle(img, PointLR, PointBR, Scalar(255, 255, 0), 1, 8,0);

参数大部分都是很好理解的,但是有一点是当线宽取值为负的时候,一般可以用CV_FILLED,绘制的矩形会将内部填充。

4.圆circle

circle的函数原型如下

可以看到圆形的绘制实际使用了两种方式EllipseEx和Circle,但是这是OpenCV内部的事情,我们可以不关心,我们需要关心的是,当thickness 为负值的时候,圆内部会被填充,其他的参数也是很好理解的。

void circle( InputOutputArray _img, Point center, int radius,const Scalar& color, int thickness, int line_type, int shift )
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( line_type == CV_AA && img.depth() != CV_8U )line_type = 8;CV_Assert( radius >= 0 && thickness <= MAX_THICKNESS &&0 <= shift && shift <= XY_SHIFT );double buf[4];scalarToRawData(color, buf, img.type(), 0);if( thickness > 1 || line_type != LINE_8 || shift > 0 ){Point2l _center(center);int64 _radius(radius);_center.x <<= XY_SHIFT - shift;_center.y <<= XY_SHIFT - shift;_radius <<= XY_SHIFT - shift;EllipseEx( img, _center, Size2l(_radius, _radius),0, 0, 360, buf, thickness, line_type );}elseCircle( img, center, radius, buf, thickness < 0 );
}

使用方法

circle(img, pointcenter, radius, Scalar(0, 0, 255), 1, 8, 0);

5.椭圆ellipse

ellipse的函数原型如下

函数的第一个定义使用的参数主要是中心点,长轴长和短轴长(通过Size axes传递),然后是angle,可以将椭圆绕中心点旋转指定的度数,这个单位是度(0-360)然后是绘制的椭圆的起始角和结束角,这意味着,绘制椭圆的时候是可以只绘制一段圆弧,这个圆弧是从x轴顺时针旋转的方向,0-180在x轴下方。同样,这里线宽如果为负数的话,图形内部会被填充,如果是弧形,会填充为扇形。
函数的第二个定义通过一个RotatedRect包含了长轴短轴和旋转角度,而起始和结束的角没有,这样设置之后实际上最后还是把参数转化为了第一个定义的参数,才进行的绘制,并且由于没有起始角和结束角的信息,这个定义失去了绘制弧线和扇形的功能,不建议使用。

void ellipse( InputOutputArray _img, Point center, Size axes,double angle, double start_angle, double end_angle,const Scalar& color, int thickness, int line_type, int shift )
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( line_type == CV_AA && img.depth() != CV_8U )line_type = 8;CV_Assert( axes.width >= 0 && axes.height >= 0 &&thickness <= MAX_THICKNESS && 0 <= shift && shift <= XY_SHIFT );double buf[4];scalarToRawData(color, buf, img.type(), 0);int _angle = cvRound(angle);int _start_angle = cvRound(start_angle);int _end_angle = cvRound(end_angle);Point2l _center(center);Size2l _axes(axes);_center.x <<= XY_SHIFT - shift;_center.y <<= XY_SHIFT - shift;_axes.width <<= XY_SHIFT - shift;_axes.height <<= XY_SHIFT - shift;EllipseEx( img, _center, _axes, _angle, _start_angle,_end_angle, buf, thickness, line_type );
}void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar& color,int thickness, int lineType)
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( lineType == CV_AA && img.depth() != CV_8U )lineType = 8;CV_Assert( box.size.width >= 0 && box.size.height >= 0 &&thickness <= MAX_THICKNESS );double buf[4];scalarToRawData(color, buf, img.type(), 0);int _angle = cvRound(box.angle);Point2l center(cvRound(box.center.x),cvRound(box.center.y));center.x = (center.x << XY_SHIFT) + cvRound((box.center.x - center.x)*XY_ONE);center.y = (center.y << XY_SHIFT) + cvRound((box.center.y - center.y)*XY_ONE);Size2l axes(cvRound(box.size.width),cvRound(box.size.height));axes.width  = (axes.width  << (XY_SHIFT - 1)) + cvRound((box.size.width - axes.width)*(XY_ONE>>1));axes.height = (axes.height << (XY_SHIFT - 1)) + cvRound((box.size.height - axes.height)*(XY_ONE>>1));EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType );
}

使用方法

使用方法基本和圆是一样的,只是多几个参数

ellipse(img, pointcenter, Size(radiusx,radiusy),0,0,360 Scalar(0, 0, 255), 1, 8, 0)

6.多边形polylines

polylines的函数原型如下

定义1 第一个参数是mat矩阵,
第二个参数为一个二维的point矩阵,一般一维的point矩阵,每两个点依次相连,可以画出一条折线,而二维的point矩阵就可以绘制多条没有交点的折线,
第三个参数是每条折线的点数,也就是说没条折线的点数可以不同,
第四个参数表示要画的线的条数,
第五个参数表示画的线是不是闭合的,也就是最后一个点和第一个点要不要连接,这里只能统一控制所以的线的状态,不能既有闭合的又有不闭合的。
剩下的参数全部是普通的画线的参数
定义2要比定义1简单很多,用来处理只需要绘制一条折线的情况,而且参数InputArrayOfArrays 是一个可以自己计算自己数组元素的个数的容器,可以是std::vector,然后基于容器的属性,会自动生成一个满足定义1的参数,最后还是使用的定义1绘制的图形,这里如果只需要绘制一条折线的话,推荐使用定义2的方法。

void polylines( InputOutputArray _img, const Point* const* pts, const int* npts, int ncontours, bool isClosed,const Scalar& color, int thickness, int line_type, int shift )
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( line_type == CV_AA && img.depth() != CV_8U )line_type = 8;CV_Assert( pts && npts && ncontours >= 0 &&0 <= thickness && thickness <= MAX_THICKNESS &&0 <= shift && shift <= XY_SHIFT );double buf[4];scalarToRawData( color, buf, img.type(), 0 );for( int i = 0; i < ncontours; i++ ){std::vector<Point2l> _pts(pts[i], pts[i]+npts[i]);PolyLine( img, _pts.data(), npts[i], isClosed, buf, thickness, line_type, shift );}
}void cv::polylines(InputOutputArray img, InputArrayOfArrays pts,bool isClosed, const Scalar& color,int thickness, int lineType, int shift)
{CV_INSTRUMENT_REGION();bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR ||pts.kind() == _InputArray::STD_VECTOR_MAT;int i, ncontours = manyContours ? (int)pts.total() : 1;if( ncontours == 0 )return;AutoBuffer<Point*> _ptsptr(ncontours);AutoBuffer<int> _npts(ncontours);Point** ptsptr = _ptsptr.data();int* npts = _npts.data();for( i = 0; i < ncontours; i++ ){Mat p = pts.getMat(manyContours ? i : -1);if( p.total() == 0 ){ptsptr[i] = NULL;npts[i] = 0;continue;}CV_Assert(p.checkVector(2, CV_32S) >= 0);ptsptr[i] = p.ptr<Point>();npts[i] = p.rows*p.cols*p.channels()/2;}polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift);
}

使用方法

这里是定义二的使用方式

polylines(Frame, LinePoints, false, cv::Scalar(255,0, 0, 255),//颜色LineWidth,//线的粗细LINE_AA););

7.文字putText

putText的函数原型如下

绘制文字第一个参数是mat
第二个参数是std::string,也就是写的内容
第三个参数是写的位置,是字符串的左上角
第四个参数是写的字体
第五个参数是字体大小
后面的是划线的参数
bottomLeftOrigin 参数控制字体是在左底部还是左顶部,默认为左底部

void putText( InputOutputArray _img, const String& text, Point org,int fontFace, double fontScale, Scalar color,int thickness, int line_type, bool bottomLeftOrigin ){CV_INSTRUMENT_REGION();if ( text.empty() ){return;}Mat img = _img.getMat();const int* ascii = getFontData(fontFace);double buf[4];scalarToRawData(color, buf, img.type(), 0);int base_line = -(ascii[0] & 15);int hscale = cvRound(fontScale*XY_ONE), vscale = hscale;if( line_type == CV_AA && img.depth() != CV_8U )line_type = 8;if( bottomLeftOrigin )vscale = -vscale;int64 view_x = (int64)org.x << XY_SHIFT;int64 view_y = ((int64)org.y << XY_SHIFT) + base_line*vscale;std::vector<Point2l> pts;pts.reserve(1 << 10);const char **faces = cv::g_HersheyGlyphs;for( int i = 0; i < (int)text.size(); i++ ){int c = (uchar)text[i];Point2l p;readCheck(c, i, text, fontFace);const char* ptr = faces[ascii[(c-' ')+1]];p.x = (uchar)ptr[0] - 'R';p.y = (uchar)ptr[1] - 'R';int64 dx = p.y*hscale;view_x -= p.x*hscale;pts.resize(0);for( ptr += 2;; ){if( *ptr == ' ' || !*ptr ){if( pts.size() > 1 )PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT );if( !*ptr++ )break;pts.resize(0);}else{p.x = (uchar)ptr[0] - 'R';p.y = (uchar)ptr[1] - 'R';ptr += 2;pts.push_back(Point2l(p.x*hscale + view_x, p.y*vscale + view_y));}}view_x += dx;}
}

opencv支持的字体包括

/** Only a subset of Hershey fonts <https://en.wikipedia.org/wiki/Hershey_fonts> are supported
@ingroup imgproc_draw
*/
enum HersheyFonts {FONT_HERSHEY_SIMPLEX        = 0, //!< normal size sans-serif fontFONT_HERSHEY_PLAIN          = 1, //!< small size sans-serif fontFONT_HERSHEY_DUPLEX         = 2, //!< normal size sans-serif font (more complex than FONT_HERSHEY_SIMPLEX)FONT_HERSHEY_COMPLEX        = 3, //!< normal size serif fontFONT_HERSHEY_TRIPLEX        = 4, //!< normal size serif font (more complex than FONT_HERSHEY_COMPLEX)FONT_HERSHEY_COMPLEX_SMALL  = 5, //!< smaller version of FONT_HERSHEY_COMPLEXFONT_HERSHEY_SCRIPT_SIMPLEX = 6, //!< hand-writing style fontFONT_HERSHEY_SCRIPT_COMPLEX = 7, //!< more complex variant of FONT_HERSHEY_SCRIPT_SIMPLEXFONT_ITALIC                 = 16 //!< flag for italic font
};

使用方法

putText(Frame, SAngle, Point, cv::FONT_HERSHEY_SIMPLEX, ScalarTextSize, Scalar(255, 0, 0, 0), ScalarTextThick);

8.不常见功能绘制标记drawMarker

drawMarker的函数原型如下

绘制标记只支持指定的几种类型,从函数定义可以看出来,实际上还是绘制的直线,所以只支持几种简单的图形

/* ----------------------------------------------------------------------------------------- */
/* ADDING A SET OF PREDEFINED MARKERS WHICH COULD BE USED TO HIGHLIGHT POSITIONS IN AN IMAGE */
/* ----------------------------------------------------------------------------------------- */void drawMarker(InputOutputArray img, Point position, const Scalar& color, int markerType, int markerSize, int thickness, int line_type)
{switch(markerType){// The cross marker casecase MARKER_CROSS:line(img, Point(position.x-(markerSize/2), position.y), Point(position.x+(markerSize/2), position.y), color, thickness, line_type);line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);break;// The tilted cross marker casecase MARKER_TILTED_CROSS:line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);break;// The star marker casecase MARKER_STAR:line(img, Point(position.x-(markerSize/2), position.y), Point(position.x+(markerSize/2), position.y), color, thickness, line_type);line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);break;// The diamond marker casecase MARKER_DIAMOND:line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y), color, thickness, line_type);line(img, Point(position.x+(markerSize/2), position.y), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x, position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y), color, thickness, line_type);line(img, Point(position.x-(markerSize/2), position.y), Point(position.x, position.y-(markerSize/2)), color, thickness, line_type);break;// The square marker casecase MARKER_SQUARE:line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x+(markerSize/2), position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x-(markerSize/2), position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);break;// The triangle up marker casecase MARKER_TRIANGLE_UP:line(img, Point(position.x-(markerSize/2), position.y+(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x+(markerSize/2), position.y+(markerSize/2)), Point(position.x, position.y-(markerSize/2)), color, thickness, line_type);line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);break;// The triangle down marker casecase MARKER_TRIANGLE_DOWN:line(img, Point(position.x-(markerSize/2), position.y-(markerSize/2)), Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);line(img, Point(position.x+(markerSize/2), position.y-(markerSize/2)), Point(position.x, position.y+(markerSize/2)), color, thickness, line_type);line(img, Point(position.x, position.y+(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);break;// If any number that doesn't exist is entered as marker type, draw a cross marker, to avoid crashesdefault:drawMarker(img, position, color, MARKER_CROSS, markerSize, thickness, line_type);break;}
}

支持的类型如下

/** Possible set of marker types used for the cv::drawMarker function
@ingroup imgproc_draw
*/
enum MarkerTypes
{MARKER_CROSS = 0,           //!< A crosshair marker shapeMARKER_TILTED_CROSS = 1,    //!< A 45 degree tilted crosshair marker shapeMARKER_STAR = 2,            //!< A star marker shape, combination of cross and tilted crossMARKER_DIAMOND = 3,         //!< A diamond marker shapeMARKER_SQUARE = 4,          //!< A square marker shapeMARKER_TRIANGLE_UP = 5,     //!< An upwards pointing triangle marker shapeMARKER_TRIANGLE_DOWN = 6    //!< A downwards pointing triangle marker shape
};

使用方法

绘制一个星号

drawMarker(Frame,Point,  Scalar(255, 0, 0, 0), cv::MARKER_STAR);

9.不常用方法,填充凸多边形内部fillConvexPoly

fillConvexPoly的函数原型如下

fillConvexPoly有两种定义,第一种定义
从定义不难发现,fillConvexPoly的时候和polylines比较相似,比较像第二种定义,只是参数使用的是数组指针和元素个数,而不是容器。
第二种定义直接使用了容器,这里的InputArray 是可以使用std::vector初始化的,然后也是转化为第一种定义执行,但是第二种明显更符合我们平时使用的习惯

void fillConvexPoly( InputOutputArray _img, const Point* pts, int npts,const Scalar& color, int line_type, int shift )
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( !pts || npts <= 0 )return;if( line_type == CV_AA && img.depth() != CV_8U )line_type = 8;double buf[4];CV_Assert( 0 <= shift && shift <=  XY_SHIFT );scalarToRawData(color, buf, img.type(), 0);std::vector<Point2l> _pts(pts, pts + npts);FillConvexPoly( img, _pts.data(), npts, buf, line_type, shift );
}void cv::fillConvexPoly(InputOutputArray img, InputArray _points,const Scalar& color, int lineType, int shift)
{CV_INSTRUMENT_REGION();Mat points = _points.getMat();CV_Assert(points.checkVector(2, CV_32S) >= 0);fillConvexPoly(img, points.ptr<Point>(), points.rows*points.cols*points.channels()/2, color, lineType, shift);
}

使用方法

fillConvexPoly(img,pPoint,npoints,Scalar(255, 0, 0, 0),LINE_AA,0)
fillConvexPoly(img,vectpoint,Scalar(255, 0, 0, 0),LINE_AA,0)

10.不常用方法,填充复杂多边形内部fillPoly

fillPoly的函数原型如下

这个函数的定义更像polylines的第一个定义,想比于fillConvexPoly,他可以绘制非凸多边形,一般fillConvexPoly用来绘制凸多边形,因为fillConvexPoly单独只处理这一种类型,所以会快一点,fillPoly用来绘制非凸多边形,比如五角星等。
参数pts,npts,ncontours的含义和多边形绘制polylines中一样
第二种定义通过使用InputArrayOfArrays ,将pts,npts,ncontours全部包含了,这个类型同样可以使用vector<vector<>> 初始化,只是简化了使用的方法。
函数的最后一个参数Point offset ,是针对所有点的偏移

void fillPoly( InputOutputArray _img, const Point** pts, const int* npts, int ncontours,const Scalar& color, int line_type,int shift, Point offset )
{CV_INSTRUMENT_REGION();Mat img = _img.getMat();if( line_type == CV_AA && img.depth() != CV_8U )line_type = 8;CV_Assert( pts && npts && ncontours >= 0 && 0 <= shift && shift <= XY_SHIFT );double buf[4];scalarToRawData(color, buf, img.type(), 0);std::vector<PolyEdge> edges;int i, total = 0;for( i = 0; i < ncontours; i++ )total += npts[i];edges.reserve( total + 1 );for (i = 0; i < ncontours; i++){std::vector<Point2l> _pts(pts[i], pts[i] + npts[i]);CollectPolyEdges(img, _pts.data(), npts[i], edges, buf, line_type, shift, offset);}FillEdgeCollection(img, edges, buf);
}void cv::fillPoly(InputOutputArray img, InputArrayOfArrays pts,const Scalar& color, int lineType, int shift, Point offset)
{CV_INSTRUMENT_REGION();bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR ||pts.kind() == _InputArray::STD_VECTOR_MAT;int i, ncontours = manyContours ? (int)pts.total() : 1;if( ncontours == 0 )return;AutoBuffer<Point*> _ptsptr(ncontours);AutoBuffer<int> _npts(ncontours);Point** ptsptr = _ptsptr.data();int* npts = _npts.data();for( i = 0; i < ncontours; i++ ){Mat p = pts.getMat(manyContours ? i : -1);CV_Assert(p.checkVector(2, CV_32S) >= 0);ptsptr[i] = p.ptr<Point>();npts[i] = p.rows*p.cols*p.channels()/2;}fillPoly(img, (const Point**)ptsptr, npts, (int)ncontours, color, lineType, shift, offset);
}

使用方法

fillPoly(img,pppoint,npts,ncounter,Scalar(255, 0, 0, 0),LINE_AA,0)
fillPoly(img,vectvectpoint,Scalar(255, 0, 0, 0),LINE_AA,0)

11.不常用方法,绘制轮廓drawContours

drawContours的函数原型如下

第一个参数表示mat矩阵
第二个参数为组成轮廓的多边形点的数组,也可以用vector<vector<>> 初始化
第三个参数contourIdx指明画第几个轮廓,如果这个参数为负值,就画全部轮廓,
第四个参数color为轮廓的颜色,
第五个参数thickness为轮廓的线宽,如果为负值(CV_FILLED)就填充轮廓内部,
第六个参数lineType为线型,
_hierarchy,maxLevel是一起使用的,只有_hierarchy有数据的时候,maxLevel才有意义。
maxLevel的值控制绘制的轮廓的层数。
@param maxLevel绘制轮廓的最大水平。 如果为0,则仅绘制指定的轮廓。
如果为1,该函数将绘制轮廓和所有嵌套轮廓。 如果为2,则函数
绘制轮廓,所有嵌套轮廓,所有从嵌套到嵌套的轮廓,依此类推。 这
仅当有可用的层次结构时,才考虑该参数

void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,int contourIdx, const Scalar& color, int thickness,int lineType, InputArray _hierarchy,int maxLevel, Point offset )
{CV_INSTRUMENT_REGION();Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();CvMat _cimage = cvMat(image);size_t ncontours = _contours.total();size_t i = 0, first = 0, last = ncontours;std::vector<CvSeq> seq;std::vector<CvSeqBlock> block;if( !last )return;seq.resize(last);block.resize(last);for( i = first; i < last; i++ )seq[i].first = 0;if( contourIdx >= 0 ){CV_Assert( 0 <= contourIdx && contourIdx < (int)last );first = contourIdx;last = contourIdx + 1;}for( i = first; i < last; i++ ){Mat ci = _contours.getMat((int)i);if( ci.empty() )continue;int npoints = ci.checkVector(2, CV_32S);CV_Assert( npoints > 0 );cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),ci.ptr(), npoints, &seq[i], &block[i] );}if( hierarchy.empty() || maxLevel == 0 )for( i = first; i < last; i++ ){seq[i].h_next = i < last-1 ? &seq[i+1] : 0;seq[i].h_prev = i > first ? &seq[i-1] : 0;}else{size_t count = last - first;CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 );const Vec4i* h = hierarchy.ptr<Vec4i>();if( count == ncontours ){for( i = first; i < last; i++ ){int h_next = h[i][0], h_prev = h[i][1],v_next = h[i][2], v_prev = h[i][3];seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;}}else{int child = h[first][2];if( child >= 0 ){addChildContour(_contours, ncontours, h, child, seq, block);seq[first].v_next = &seq[child];}}}cvDrawContours( &_cimage, &seq[first], cvScalar(color), cvScalar(color), contourIdx >= 0 ?-maxLevel : maxLevel, thickness, lineType, cvPoint(offset) );
}

findContours

void cv::findContours( InputArray _image, OutputArrayOfArrays _contours,OutputArray _hierarchy, int mode, int method, Point offset )
{CV_INSTRUMENT_REGION();// Sanity check: output must be of type vector<vector<Point>>CV_Assert((_contours.kind() == _InputArray::STD_VECTOR_VECTOR || _contours.kind() == _InputArray::STD_VECTOR_MAT ||_contours.kind() == _InputArray::STD_VECTOR_UMAT));CV_Assert(_contours.empty() || (_contours.channels() == 2 && _contours.depth() == CV_32S));Mat image0 = _image.getMat(), image;Point offset0(0, 0);if(method != CV_LINK_RUNS){offset0 = Point(-1, -1);copyMakeBorder(image0, image, 1, 1, 1, 1, BORDER_CONSTANT | BORDER_ISOLATED, Scalar(0));}else{image = image0;}MemStorage storage(cvCreateMemStorage());CvMat _cimage = cvMat(image);CvSeq* _ccontours = 0;if( _hierarchy.needed() )_hierarchy.clear();cvFindContours_Impl(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, cvPoint(offset0 + offset), 0);if( !_ccontours ){_contours.clear();return;}Seq<CvSeq*> all_contours(cvTreeToNodeSeq( _ccontours, sizeof(CvSeq), storage ));int i, total = (int)all_contours.size();_contours.create(total, 1, 0, -1, true);SeqIterator<CvSeq*> it = all_contours.begin();for( i = 0; i < total; i++, ++it ){CvSeq* c = *it;((CvContour*)c)->color = (int)i;_contours.create((int)c->total, 1, CV_32SC2, i, true);Mat ci = _contours.getMat(i);CV_Assert( ci.isContinuous() );cvCvtSeqToArray(c, ci.ptr());}if( _hierarchy.needed() ){_hierarchy.create(1, total, CV_32SC4, -1, true);Vec4i* hierarchy = _hierarchy.getMat().ptr<Vec4i>();it = all_contours.begin();for( i = 0; i < total; i++, ++it ){CvSeq* c = *it;int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;int h_prev = c->h_prev ? ((CvContour*)c->h_prev)->color : -1;int v_next = c->v_next ? ((CvContour*)c->v_next)->color : -1;int v_prev = c->v_prev ? ((CvContour*)c->v_prev)->color : -1;hierarchy[i] = Vec4i(h_next, h_prev, v_next, v_prev);}}
}void cv::findContours( InputArray _image, OutputArrayOfArrays _contours,int mode, int method, Point offset)
{CV_INSTRUMENT_REGION();findContours(_image, _contours, noArray(), mode, method, offset);
}取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
取值二:CV_RETR_LIST   检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到
取值三:CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层
取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内
取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留
取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

绘制类型mode

绘制的类型定义了几种常见的,但是从drawContours的定义来说,应该有更多种类。

/** Contour retrieval modes */
enum
{CV_RETR_EXTERNAL=0,CV_RETR_LIST=1,CV_RETR_CCOMP=2,CV_RETR_TREE=3,CV_RETR_FLOODFILL=4
};
/** Contour approximation methods */
enum
{CV_CHAIN_CODE=0,CV_CHAIN_APPROX_NONE=1,CV_CHAIN_APPROX_SIMPLE=2,CV_CHAIN_APPROX_TC89_L1=3,CV_CHAIN_APPROX_TC89_KCOS=4,CV_LINK_RUNS=5
};

使用方法

CV_EXPORTS_W void findContours( InputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset = Point());

/** @overload */
CV_EXPORTS void findContours( InputArray image, OutputArrayOfArrays contours,
int mode, int method, Point offset = Point());

drawContours一般配合findContours一起使用

 vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(img, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);Mat resultImage = Mat ::zeros(img.size(),CV_8U);drawContours(resultImage, contours, -1, Scalar(255, 0, 255));

OpenCv绘制简单的几何图形相关推荐

  1. 如何使用OpenCV绘制简单的几何图形?

    要使用OpenCV绘制图形,除了cv2库之外,我们还需要便于进行矩阵操作的numpy库: import cv2 as cv import numpy as np 空白窗口 先展示代码: blank = ...

  2. python+OpenCV图像处理(三)绘制简单的几何图形、显示文字

    绘制简单的几何图形.显示文字 (一)绘制直线和矩形 img = np.zeros([512, 512, 3]) # line函数用来画直线,第一个参数可以理解为画布矩阵, # 第二个参数pt1是直线的 ...

  3. python opencv 绘制简单图形

    09-python opencv 绘制简单图形 09-python opencv 绘制简单图形 概述 实现过程 引用与创建空图 绘制直线 绘制矩形 绘制圆 绘制椭圆 添加文字 显示图像 源代码 运行结 ...

  4. OpenGL入门学习[二] 绘制简单的几何图形

    OpenGL入门学习[二] 本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念. 一.点.直线和多边形 我们知道数学(具体的说,是几何学)中有点.直线和多边形的概念,但这些概念 ...

  5. 用canvas绘制简单的几何图形

    文章目录 添加canvas 调用canvas的API接口 绘制简单的图形 直线 三角形 矩形 圆 清空画布 canvas是一块矩形区域,相当于一块画布.它本身不具有绘图功能,绘图功能主要是由JavaS ...

  6. openCV绘制简单Sierpinski(分形)图形

    运行环境:openCV4 C++ X64 对于分形图像一般具有一个主要性质 自相似性 分形图形的局部和整体一般具有相似的结构,细节上具有递归的特性,细节可以达到无限小,但是可以预测. 我们利用这个性质 ...

  7. 2.绘制简单的几何图形

    一.点.直线和多边形 数学上的点,只有位置,没有大小.但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点.另一方面,无论图形输出设备如何精确, 始终不能输出一个无穷小的点.一般情况下,Op ...

  8. 10、OpenCV绘制几何图形

    OpenCV绘制几何图形 一.学习目标 二.OpenCV中点和颜色标量的表示 三.绘制不同的几何形状 四.完整代码示例 一.学习目标 了解点和颜色标量的数据结构对象 学会使用OpenCV画直线段 学会 ...

  9. [Python从零到壹] 三十五.图像处理基础篇之OpenCV绘制各类几何图形

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

最新文章

  1. 信息技术守护人类文明DNA
  2. redis管道的使用
  3. org.springframework.dao.InvalidDataAccessApiUsageException
  4. laravel插入数据时报 502 Bad Gateway
  5. 28个数控编程代码大全,众多程序员呕心沥血的私货
  6. js遍历对象去除空格
  7. excel教程自学网_Excel零基础入门到高级自学视频教程
  8. 大华出入口管理系统H710服务器配置,DH-DSS-H710S2 大华出入口综合管理系统 人员车辆管理车场收费...
  9. 设计模式23模式介绍
  10. 前端学习——Web版自定义2048+移动端适应
  11. Jenkins:安装出现“该jenkins实例似乎已离线”问题解决
  12. 2021-2027全球与中国单向拉伸聚丙烯薄膜市场现状及未来发展趋势
  13. pycharm远程连接服务器中的docker容器的配置
  14. 智联“焊”界,数字未来
  15. 华为十年(转贴)原华为牛人写的
  16. 20.创新与企业家精神——结论,企业家社会
  17. Python:模拟邮箱登陆
  18. flex布局,构建一个响应式的后台网站
  19. 基于USB2.0的视频图像处理芯片实现方案
  20. 亿康先达的全球研究揭示第一代首席数字官面临的挑战

热门文章

  1. jstl自定义标签问题Unable to find taglib
  2. SpringBoot项目中测试数据库是否连通
  3. 学习笔记 | 多水平logistics模型
  4. 云压广告怎么彻底删除_彻底删除微信记录有哪些方法,听听专业人士怎么说!...
  5. 递归算法 -- 计算n!(n的阶乘)
  6. Fbx导入Unity穿模
  7. 【技巧】Pandas使用drop后使用reset_index重置索性
  8. 89c52单片机c语言延时程序计算 脉冲,89C52单片机定时器延时时间的计算与程序解析 - STC89C52单片机定时器/计数器详解(含程序和定时器2)...
  9. parted分区工具使用
  10. Python+django+xadmin学习与开发笔记【03】慕课平台开发之数据库设计