本文实例为大家分享了OpenCV绘制图形功能的具体代码,供大家参考,具体内容如下
1、绘制直线
绘制直线函数是cv::line,函数完整形式如下
1
2
3
4
5
6
7
8
9
10
|
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0); /* @param img 图像 @param pt1 线段端点1 @param pt2 线段端点2 @param color 线段颜色 @param thickness 线宽 @param lineType 线的类型 @param shift 点坐标的小数位偏移 */ |
color可以使用cv::Scalar构造,但是传入参数的顺序是BGR,使用CV_RGB宏更直观,以RGB顺序传入;
lineType取值有LINE_4、LINE_8和LINE_AA,分别表示4连接线,8连接线,抗锯齿线,是以不同的算法产生直线(也可以是FILLED=-1,直接填充);
shift是指点坐标的二进制表示的位偏移,每加1坐标值减一半,实验的结果,不知道理解的对不对,使用默认值0就可以了;
在两个点之间绘制线宽为1的红色直线定义为一个函数
1
2
3
4
|
void DrawLine( const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::line(destImg, pt1, pt2, CV_RGB(255, 0, 0), 1); } |
下面的实例在鼠标两次点击位置中间画一根直线,绘制完成可以按Enter键保存图像。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
cv::Mat g_originImage; //原始图像 cv::Mat g_editImage; //编辑的图像 std::vector<cv::Point> g_editPoints; //正在绘制的图形的点 std::vector<std::vector<cv::Point>> g_lines; //所有的线段 void RedrawAllLines() { g_originImage.copyTo(g_editImage); //恢复背景图像 for ( int i = 0; i < g_lines.size(); i++) { if (g_lines[i].size() >= 2) { DrawLine(g_editImage,g_lines[i][0], g_lines[i][1]); } } } void OnDrawLineMouseEvent( int event, int x, int y, int flags, void * userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { //在第二个点按下鼠标之后添加到线段列表中,并重绘图像 g_editPoints.push_back(cv::Point(x, y)); g_lines.push_back(g_editPoints); RedrawAllLines(); g_editPoints.clear(); imshow( "image" , g_editImage); } else { g_editPoints.push_back(cv::Point(x, y)); //第一个点 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { //鼠标移动中,绘制到鼠标位置的直线,但鼠标当前点不加入到g_editPoints中 RedrawAllLines(); DrawLine(g_editImage,g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow( "image" , g_editImage); } } } int main( int argc, char **arv) { g_originImage = cv::imread( "walkers.jpg" ); g_originImage.copyTo(g_editImage); cv::namedWindow( "image" ); imshow( "image" , g_editImage); cv::setMouseCallback( "image" , OnDrawLineMouseEvent); int key = cv::waitKey(0); while (key != 27) { if (key == 13) { cv::imwrite( "testsave.png" , g_editImage); } key = cv::waitKey(0); } return 0; } |
2、绘制圆
绘制圆的函数cv::circle
1
2
3
4
5
6
7
8
9
10
|
void circle(InputOutputArray img, Point center, int radius, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0); /* @param img 图像 @param center 圆心 @param radius 半径 @param color 线颜色 @param thickness 线宽,如果小于0则填充圆 @param lineType 线类型 @param shift 圆心和半径值的位偏移 */ |
以两个点画一个圆,第一个点为圆心,两点距离为圆半径,定义为一个函数DrawCircle
1
2
3
4
5
6
|
void DrawCircle( const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::Point deltaPt = pt2 - pt1; float radius = cv:: sqrt (deltaPt.x*deltaPt.x + deltaPt.y*deltaPt.y); cv::circle(destImg, pt1, radius, CV_RGB(255, 0, 0), 1); } |
以下示例实现鼠标点击两次绘制如上的一个圆,main函数与画直线一样,只要将鼠标事件回调改成OnDrawCircleMouseEvent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
std::vector<std::vector<cv::Point>> g_circles; //所有的圆 void RedrawAllCircles() { g_originImage.copyTo(g_editImage); //恢复背景图像 for ( int i = 0; i < g_circles.size(); i++) { if (g_circles[i].size() >= 2) { DrawCircle(g_editImage, g_circles[i][0], g_circles[i][1]); } } } void OnDrawCircleMouseEvent( int event, int x, int y, int flags, void * userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); g_circles.push_back(g_editPoints); RedrawAllCircles(); g_editPoints.clear(); imshow( "image" , g_editImage); } else { g_editPoints.push_back(cv::Point(x, y)); //第一个点 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllCircles(); DrawCircle(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow( "image" , g_editImage); } } } |
3、绘制椭圆
绘制椭圆的函数cv::ellipse,有两种形式,其中一个定义如下
1
2
3
4
5
6
7
8
|
void ellipse(InputOutputArray img, const RotatedRect& box, const Scalar& color, int thickness = 1, int lineType = LINE_8); /* @param img 图像 @param box 可以调整旋转角度的矩形 @param color 线颜色 @param thickness 线宽,如果小于0则填充椭圆 @param lineType 线类型 */ |
以两个点组成的矩形内画一个椭圆,定义为函数DrawEllipse,这里不考虑矩形的旋转,固定为0
1
2
3
4
5
6
|
void DrawEllipse( const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::Point2f center = cv::Point2f((pt1.x + pt2.x) / 2.0, (pt1.y + pt2.y) / 2.0); cv::Point2f size = cv::Point2f(cv:: abs (pt2.x - pt1.x), cv:: abs (pt2.y - pt1.y)); cv::ellipse(destImg,cv::RotatedRect(center, size, 0),CV_RGB(255, 0, 0), 1); } |
以下示例实现在鼠标两次点击位置中间画一个椭圆,main函数与画直线一样,将鼠标事件回调改成OnDrawEllipseMouseEvent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
std::vector<std::vector<cv::Point>> g_ellipses; //所有的椭圆 void RedrawAllEllipses() { g_originImage.copyTo(g_editImage); //恢复背景图像 for ( int i = 0; i < g_ellipses.size(); i++) { if (g_ellipses[i].size() >= 2) { DrawEllipse(g_editImage, g_ellipses[i][0], g_ellipses[i][1]); } } } void OnDrawEllipseMouseEvent( int event, int x, int y, int flags, void * userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); g_ellipses.push_back(g_editPoints); RedrawAllEllipses(); g_editPoints.clear(); imshow( "image" , g_editImage); } else { g_editPoints.push_back(cv::Point(x, y)); //第一个点 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllEllipses(); DrawEllipse(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow( "image" , g_editImage); } } } |
4、绘制矩形
绘制矩形的函数cv::rectangle,有两种形式,其中一个定义如下
1
2
3
4
5
6
7
8
9
|
void rectangle(InputOutputArray img, Rect rec, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0); /* @param img 图像 @param rec 矩形坐标 @param color 线颜色 @param thickness 线宽,如果小于0则填充椭圆 @param lineType 线类型 @param shift 点坐标位偏移 */ |
在两个点间画一个矩形,定义为函数DrawRectangle
1
2
3
4
|
void DrawRectangle( const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::rectangle(destImg, cv::Rect(pt1, pt2), CV_RGB(255, 0, 0), 1); } |
以下示例实现在鼠标两次点击位置中间画一个矩形,main函数与画直线一样,将鼠标事件回调改成OnDrawRectangleMouseEvent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
std::vector<std::vector<cv::Point>> g_rectangles; //所有的矩形 void RedrawAllRectangles() { g_originImage.copyTo(g_editImage); //恢复背景图像 for ( int i = 0; i < g_rectangles.size(); i++) { if (g_rectangles[i].size() >= 2) { DrawRectangle(g_editImage, g_rectangles[i][0], g_rectangles[i][1]); } } } void OnDrawRectangleMouseEvent( int event, int x, int y, int flags, void * userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); g_rectangles.push_back(g_editPoints); RedrawAllRectangles(); g_editPoints.clear(); imshow( "image" , g_editImage); } else { g_editPoints.push_back(cv::Point(x, y)); //第一个点 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllRectangles(); DrawRectangle(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow( "image" , g_editImage); } } } |
5、绘制多边形轮廓
绘制多边形的函数cv::polylines,有两种形式,其中一个定义如下
1
2
3
4
5
6
7
8
9
10
|
void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0 ); /* @param img 图像 @param pts 多边形坐标数组 @param isClosed 是否绘制闭合多边形 @param color 线颜色 @param thickness 线宽 @param lineType 线类型 @param shift 点坐标位偏移 */ |
这里的pts是一个2维数组,表示多个多边形,以下分别实现绘制多个多边形和单个多边形的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
|
void DrawMultiPolys( const cv::Mat& destImg, const std::vector<std::vector<cv::Point>>& points, bool bClose) { cv::polylines(destImg, points, bClose, CV_RGB(255, 0, 0), 1); } void DrawOnePoly( const cv::Mat& destImg, const std::vector<cv::Point>& points, bool bClose) { if (points.size() >= 2) { std::vector<std::vector<cv::Point>> polyPoints; polyPoints.push_back(points); DrawMultiPolys(destImg,polyPoints,bClose); } } |
以下示例实现在鼠标多次点击的位置绘制多边形,main函数与画直线一样,将鼠标事件回调改成OnDrawPolyMouseEvent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
std::vector<std::vector<cv::Point>> g_polys; //所有的多边形 void RedrawAllPolys() { g_originImage.copyTo(g_editImage); //恢复背景图像 DrawMultiPolys(g_editImage,g_polys, true ); } void OnDrawPolyMouseEvent( int event, int x, int y, int flags, void * userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); RedrawAllPolys(); DrawOnePoly(g_editImage, g_editPoints, false ); //正在绘制的多边形要单独画,而且不能闭合 imshow( "image" , g_editImage); } else { g_editPoints.push_back(cv::Point(x, y)); //第一个点 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllPolys(); DrawOnePoly(g_editImage,g_editPoints, false ); //正在绘制的多边形要单独画,而且不能闭合 DrawLine(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); //绘制一根到鼠标位置的直线 imshow( "image" , g_editImage); } } else if (event == cv::EVENT_RBUTTONDOWN) { //右键按下结束多边形绘制,加入到g_polys g_polys.push_back(g_editPoints); RedrawAllPolys(); g_editPoints.clear(); cv::imshow( "image" , g_editImage); } } |
6、绘制填充多边形
绘制填充多边形函数cv::fillPoly,有两种形式,其中一个定义如下
1
2
3
4
5
6
7
8
9
|
void fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color, int lineType = LINE_8, int shift = 0,Point offset = Point() ); /* @param img 图像 @param pts 多边形坐标数组 @param color 线颜色 @param lineType 线类型 @param shift 点坐标位偏移 @param offset 所有多边形点的偏移 */ |
绘制填充多边形与绘制多边形轮廓差不多,只要将polylines换成fillpoly
1
2
3
4
5
6
7
8
9
10
11
12
13
|
void DrawMultiPolys( const cv::Mat& destImg, const std::vector<std::vector<cv::Point>>& points) { cv::fillPoly(destImg, points,CV_RGB(255, 0, 0)); } void DrawOnePoly( const cv::Mat& destImg, const std::vector<cv::Point>& points) { if (points.size() >= 2) { std::vector<std::vector<cv::Point>> polyPoints; polyPoints.push_back(points); DrawMultiPolys(destImg,polyPoints); } } |
如果将上面的所有功能以一定方式组合起来,就可以在图像上绘制多种形状图形并保存了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/yb0022/article/details/98760168