OpenCV学习笔记(5)_ ellipse绘制函数浅析
文章目录
1. ellipse第一种重载——绘制椭圆弧
1.1 函数原型
OpenCV的ellipse函数有两种重载方式,下面首先来试一下第一种重载方式:
OpenCV文档中对于第一种重载方式的调用如下原型:
void cv::ellipse( InputOutputArray img,
Point center,
Size axes,
double angle,
double startAngle,
double endAngle,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
int shift = 0
)
从这个函数原型中我们可以看出,第一种重载方式,可以由椭圆的中心点坐标center,椭圆的长短轴axes,起始的角度angle,弧段的起讫角度startangle和endangle,以及绘制相关的颜色、线宽、线型、坐标偏移参数来进行椭圆的绘制。
1.2 参数解析
在OpenCV的文档中,为了说明具体的角方向定义、轴方向定义等,还给出了如下的示意图:
但笔者认为这个示意图有些不太清楚的地方,于是补充并修正了一些内容,给出如下示意图:
这两张图是第一种重载方式的参数重点,下面来重点讲述一下:
- 对于第一种情况,椭圆的axes.width > axes.height;
- 注意对照示意图,axes.width表示的是椭圆的主轴,即FIRST AXIS,axes.height表示的是椭圆的副轴,即SECOND AXIS,主轴的方向沿图像坐标轴X轴顺时针偏移的方向即为angle;
- 以主轴axes.width为半径虚拟一个圆,以主轴为基准,顺时针方向偏移start angle角度,得到起始弧段点,由这个点向椭圆主轴做投影,在椭圆弧上的投影点作为椭圆弧段的真正起始点;
- 椭圆弧段的真正结束点也是采取相同的方式获得;
- 沿顺时针方向,将椭圆弧段的起始点和结束点之间的椭圆弧段绘制出来,即为图中的深蓝色弧,为该模式下绘制出的椭圆弧段;
- 注意在这种绘制模式下,axes.width和awes.height均表示的是椭圆的半轴长度,这和下一种模式会有区别;
- 对于第二种情况,即椭圆的axes.width < axes.height时,仍将axes.width所在的轴作为主轴,和第一种情况类似,也仍是以axes.width作为半径虚拟一个圆,各种偏移角、起始角、结束角均与第一种情况类似。
1.3 绘制示例
下面就来实践一把,看一看绘制的实际情况:
#define _CRT_SECURE_NO_WARNINGS
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
// ellipse 第一种重载的绘制
Point ecenter;
Size ax1, ax2;
double angle;
double startangle;
double endangle;
Mat pic1 = Mat::zeros(Size(512, 512), CV_8UC3);
Mat pic2 = Mat::zeros(Size(512, 512), CV_8UC3);
ecenter.x = 256;
ecenter.y = 256;
ax1.width = 200;
ax1.height = 100;
angle = 30;
startangle = 20;
endangle = 150;
ellipse(pic1, ecenter, ax1, angle, 0, 360, Scalar(0, 255, 0), 1, LINE_AA, 0);
ellipse(pic1, ecenter, ax1, angle, startangle, endangle, Scalar(0, 0, 255), 2, LINE_AA, 0);
putText(pic1, "AXES.WIDTH > AXES.HEIGHT", Point(25, 25), FONT_HERSHEY_PLAIN, 1, Scalar(0, 255, 0));
imshow("ellipseExample1", pic1);
ax2.width = 100;
ax2.height = 200;
ellipse(pic2, ecenter, ax2, angle, 0, 360, Scalar(0, 255, 0), 1, LINE_AA, 0);
ellipse(pic2, ecenter, ax2, angle, startangle, endangle, Scalar(0, 0, 255), 2, LINE_AA, 0);
putText(pic2, "AXES.WIDTH < AXES.HEIGHT", Point(25, 25), FONT_HERSHEY_PLAIN, 1, Scalar(0, 255, 0));
imshow("ellipseExample2", pic2);
waitKey(0);
return EXIT_SUCCESS;
}
注意其中的参数:
- 椭圆中心点坐标为(256,256);
- 椭圆的长轴半径为200,短轴半径为100;
- 第一种设置下长轴为主轴,第二种设置下短轴为主轴;
- 当startangle和endangle分别设置为0和360时,可以把整个椭圆完整绘制出来,即为结果图中的绿色椭圆;
- 红色弧段为绘制出来的椭圆弧段:
2. ellipse第二种重载——RotatedRect方式绘制椭圆
接下来这种方式,OpenCV给出了一种数据结构 RotatedRect 来存储椭圆的相关信息。
2.1 ellipse函数原型
void cv::ellipse( InputOutputArray img,
const RotatedRect & box,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8
)
相较于第一种重载方式,这种方式将椭圆的形状参数全部归并到一个RotatedRect对象即box中。
RotatedRect共有三个属性:
分别是angle center size
这个数据结构的理解很容易:center表示矩形的中心点;angle表示矩形顺时针偏转的角度;size中分别表示矩形的width和height。
注意RotatedRect中,size.width也是作为主轴存在的。
2.2 ellipse绘制示例
#define _CRT_SECURE_NO_WARNINGS
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
// ellipse 第一种重载的绘制
Point ecenter;
Size ax1, ax2;
double angle;
double startangle;
double endangle;
ecenter.x = 256;
ecenter.y = 256;
angle = 30;
startangle = 20;
endangle = 150;
// ellipse 第二种重载的绘制
RotatedRect e1;
Mat pic3 = Mat::zeros(Size(512, 512), CV_8UC3);
e1.center = ecenter;
e1.size.width = 400;
e1.size.height = 200;
e1.angle = angle;
ellipse(pic3, e1, Scalar(255, 0, 0), 1, LINE_AA);
imshow("ellipseExample3", pic3);
waitKey(0);
return EXIT_SUCCESS;
}
这里注意,size.width和size.height和第一种重载模式中不同,分别对应椭圆的主轴长和副轴长,而不是半轴长。所以我们从代码中能看到, e1.size.width
设置为400, e1.size.height
设置为200。如此绘制出来的椭圆才和第一种重载模式中的完整椭圆大小一致。
【创作不易,水平有限,如有错漏,轻喷勿骂】