经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
OpenCV绘制图形功能
来源:jb51  时间:2022/1/19 13:44:23  对本文有异议

本文实例为大家分享了OpenCV绘制图形功能的具体代码,供大家参考,具体内容如下

1、绘制直线

绘制直线函数是cv::line,函数完整形式如下

  1. void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
  2. /*
  3. @param img 图像
  4. @param pt1 线段端点1
  5. @param pt2 线段端点2
  6. @param color 线段颜色
  7. @param thickness 线宽
  8. @param lineType 线的类型
  9. @param shift 点坐标的小数位偏移
  10. */

color可以使用cv::Scalar构造,但是传入参数的顺序是BGR,使用CV_RGB宏更直观,以RGB顺序传入;

lineType取值有LINE_4、LINE_8和LINE_AA,分别表示4连接线,8连接线,抗锯齿线,是以不同的算法产生直线(也可以是FILLED=-1,直接填充);

shift是指点坐标的二进制表示的位偏移,每加1坐标值减一半,实验的结果,不知道理解的对不对,使用默认值0就可以了;

在两个点之间绘制线宽为1的红色直线定义为一个函数

  1. void DrawLine(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2)
  2. {
  3. ? ? cv::line(destImg, pt1, pt2, CV_RGB(255, 0, 0), 1);
  4. }

下面的实例在鼠标两次点击位置中间画一根直线,绘制完成可以按Enter键保存图像。

  1. cv::Mat g_originImage;//原始图像
  2. cv::Mat g_editImage;//编辑的图像
  3. std::vector<cv::Point> g_editPoints;//正在绘制的图形的点
  4. std::vector<std::vector<cv::Point>> g_lines;//所有的线段
  5. ?
  6. void RedrawAllLines()
  7. {
  8. ? ? g_originImage.copyTo(g_editImage);//恢复背景图像
  9. ? ? for (int i = 0; i < g_lines.size(); i++)
  10. ? ? {
  11. ? ? ? ? if (g_lines[i].size() >= 2)
  12. ? ? ? ? {
  13. ? ? ? ? ? ? DrawLine(g_editImage,g_lines[i][0], g_lines[i][1]);
  14. ? ? ? ? }
  15. ? ? }
  16. }
  17. void OnDrawLineMouseEvent(int event, int x, int y, int flags, void* userdata)
  18. {
  19. ? ? if (event == cv::EVENT_LBUTTONDOWN)
  20. ? ? {
  21. ? ? ? ? if (g_editPoints.size() > 0)
  22. ? ? ? ? {
  23. ? ? ? ? ? ? //在第二个点按下鼠标之后添加到线段列表中,并重绘图像
  24. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));
  25. ? ? ? ? ? ? g_lines.push_back(g_editPoints);
  26. ? ? ? ? ? ? RedrawAllLines();
  27. ? ? ? ? ? ? g_editPoints.clear();
  28. ? ? ? ? ? ? imshow("image", g_editImage);
  29. ? ? ? ? }
  30. ? ? ? ? else
  31. ? ? ? ? {
  32. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));//第一个点
  33. ? ? ? ? }
  34. ? ? }
  35. ? ? else if (event == cv::EVENT_MOUSEMOVE)
  36. ? ? {
  37. ? ? ? ? if (g_editPoints.size() > 0)
  38. ? ? ? ? {
  39. ? ? ? ? ? ? //鼠标移动中,绘制到鼠标位置的直线,但鼠标当前点不加入到g_editPoints中
  40. ? ? ? ? ? ? RedrawAllLines();
  41. ? ? ? ? ? ? DrawLine(g_editImage,g_editPoints[g_editPoints.size() - 1], cv::Point(x, y));
  42. ? ? ? ? ? ? imshow("image", g_editImage);
  43. ? ? ? ? }
  44. ? ? }
  45. }
  46. ?
  47. int main(int argc, char **arv)
  48. {
  49. ? ? g_originImage = cv::imread("walkers.jpg");
  50. ? ? g_originImage.copyTo(g_editImage);
  51. ? ? cv::namedWindow("image");
  52. ? ? imshow("image", g_editImage);
  53. ? ? cv::setMouseCallback("image", OnDrawLineMouseEvent);
  54. ? ? int key = cv::waitKey(0);
  55. ? ? while (key != 27)
  56. ? ? {
  57. ? ? ? ? if (key == 13)
  58. ? ? ? ? {
  59. ? ? ? ? ? ? cv::imwrite("testsave.png", g_editImage);
  60. ? ? ? ? }
  61. ? ? ? ? key = cv::waitKey(0);
  62. ? ? }
  63. ? ? return 0;
  64. }

2、绘制圆

绘制圆的函数cv::circle

  1. void circle(InputOutputArray img, Point center, int radius,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);
  2. /*
  3. @param img 图像
  4. @param center 圆心
  5. @param radius 半径
  6. @param color 线颜色
  7. @param thickness 线宽,如果小于0则填充圆
  8. @param lineType 线类型
  9. @param shift 圆心和半径值的位偏移
  10. */

以两个点画一个圆,第一个点为圆心,两点距离为圆半径,定义为一个函数DrawCircle

  1. void DrawCircle(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2)
  2. {
  3. ? ? cv::Point deltaPt = pt2 - pt1;
  4. ? ? float radius = cv::sqrt(deltaPt.x*deltaPt.x + deltaPt.y*deltaPt.y);
  5. ? ? cv::circle(destImg, pt1, radius, CV_RGB(255, 0, 0), 1);
  6. }

以下示例实现鼠标点击两次绘制如上的一个圆,main函数与画直线一样,只要将鼠标事件回调改成OnDrawCircleMouseEvent

  1. std::vector<std::vector<cv::Point>> g_circles;//所有的圆
  2. ?
  3. void RedrawAllCircles()
  4. {
  5. ? ? g_originImage.copyTo(g_editImage);//恢复背景图像
  6. ? ? for (int i = 0; i < g_circles.size(); i++)
  7. ? ? {
  8. ? ? ? ? if (g_circles[i].size() >= 2)
  9. ? ? ? ? {
  10. ? ? ? ? ? ? DrawCircle(g_editImage, g_circles[i][0], g_circles[i][1]);
  11. ? ? ? ? }
  12. ? ? }
  13. }
  14. void OnDrawCircleMouseEvent(int event, int x, int y, int flags, void* userdata)
  15. {
  16. ? ? if (event == cv::EVENT_LBUTTONDOWN)
  17. ? ? {
  18. ? ? ? ? if (g_editPoints.size() > 0)
  19. ? ? ? ? {
  20. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));
  21. ? ? ? ? ? ? g_circles.push_back(g_editPoints);
  22. ? ? ? ? ? ? RedrawAllCircles();
  23. ? ? ? ? ? ? g_editPoints.clear();
  24. ? ? ? ? ? ? imshow("image", g_editImage);
  25. ? ? ? ? }
  26. ? ? ? ? else
  27. ? ? ? ? {
  28. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));//第一个点
  29. ? ? ? ? }
  30. ? ? }
  31. ? ? else if (event == cv::EVENT_MOUSEMOVE)
  32. ? ? {
  33. ? ? ? ? if (g_editPoints.size() > 0)
  34. ? ? ? ? {
  35. ? ? ? ? ? ? RedrawAllCircles();
  36. ? ? ? ? ? ? DrawCircle(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y));
  37. ? ? ? ? ? ? imshow("image", g_editImage);
  38. ? ? ? ? }
  39. ? ? }
  40. }

3、绘制椭圆

绘制椭圆的函数cv::ellipse,有两种形式,其中一个定义如下

  1. void ellipse(InputOutputArray img, const RotatedRect& box, const Scalar& color,int thickness = 1, int lineType = LINE_8);
  2. /*
  3. @param img 图像
  4. @param box 可以调整旋转角度的矩形
  5. @param color 线颜色
  6. @param thickness 线宽,如果小于0则填充椭圆
  7. @param lineType 线类型
  8. */

以两个点组成的矩形内画一个椭圆,定义为函数DrawEllipse,这里不考虑矩形的旋转,固定为0

  1. void DrawEllipse(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2)
  2. {
  3. ? ? cv::Point2f center = cv::Point2f((pt1.x + pt2.x) / 2.0, (pt1.y + pt2.y) / 2.0);
  4. ? ? cv::Point2f size = cv::Point2f(cv::abs(pt2.x - pt1.x), cv::abs(pt2.y - pt1.y));
  5. ? ? cv::ellipse(destImg,cv::RotatedRect(center, size, 0),CV_RGB(255, 0, 0), 1);
  6. }

以下示例实现在鼠标两次点击位置中间画一个椭圆,main函数与画直线一样,将鼠标事件回调改成OnDrawEllipseMouseEvent

  1. std::vector<std::vector<cv::Point>> g_ellipses;//所有的椭圆
  2. void RedrawAllEllipses()
  3. {
  4. ? ? g_originImage.copyTo(g_editImage);//恢复背景图像
  5. ? ? for (int i = 0; i < g_ellipses.size(); i++)
  6. ? ? {
  7. ? ? ? ? if (g_ellipses[i].size() >= 2)
  8. ? ? ? ? {
  9. ? ? ? ? ? ? DrawEllipse(g_editImage, g_ellipses[i][0], g_ellipses[i][1]);
  10. ? ? ? ? }
  11. ? ? }
  12. }
  13. void OnDrawEllipseMouseEvent(int event, int x, int y, int flags, void* userdata)
  14. {
  15. ? ? if (event == cv::EVENT_LBUTTONDOWN)
  16. ? ? {
  17. ? ? ? ? if (g_editPoints.size() > 0)
  18. ? ? ? ? {
  19. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));
  20. ? ? ? ? ? ? g_ellipses.push_back(g_editPoints);
  21. ? ? ? ? ? ? RedrawAllEllipses();
  22. ? ? ? ? ? ? g_editPoints.clear();
  23. ? ? ? ? ? ? imshow("image", g_editImage);
  24. ? ? ? ? }
  25. ? ? ? ? else
  26. ? ? ? ? {
  27. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));//第一个点
  28. ? ? ? ? }
  29. ? ? }
  30. ? ? else if (event == cv::EVENT_MOUSEMOVE)
  31. ? ? {
  32. ? ? ? ? if (g_editPoints.size() > 0)
  33. ? ? ? ? {
  34. ? ? ? ? ? ? RedrawAllEllipses();
  35. ? ? ? ? ? ? DrawEllipse(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y));
  36. ? ? ? ? ? ? imshow("image", g_editImage);
  37. ? ? ? ? }
  38. ? ? }
  39. }

4、绘制矩形

绘制矩形的函数cv::rectangle,有两种形式,其中一个定义如下

  1. void rectangle(InputOutputArray img, Rect rec,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);
  2. /*
  3. @param img 图像
  4. @param rec 矩形坐标
  5. @param color 线颜色
  6. @param thickness 线宽,如果小于0则填充椭圆
  7. @param lineType 线类型
  8. @param shift ?点坐标位偏移
  9. */

在两个点间画一个矩形,定义为函数DrawRectangle

  1. void DrawRectangle(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2)
  2. {
  3. ? ? cv::rectangle(destImg, cv::Rect(pt1, pt2), CV_RGB(255, 0, 0), 1);
  4. }

以下示例实现在鼠标两次点击位置中间画一个矩形,main函数与画直线一样,将鼠标事件回调改成OnDrawRectangleMouseEvent

  1. ?std::vector<std::vector<cv::Point>> g_rectangles;//所有的矩形
  2. void RedrawAllRectangles()
  3. {
  4. ? ? g_originImage.copyTo(g_editImage);//恢复背景图像
  5. ? ? for (int i = 0; i < g_rectangles.size(); i++)
  6. ? ? {
  7. ? ? ? ? if (g_rectangles[i].size() >= 2)
  8. ? ? ? ? {
  9. ? ? ? ? ? ? DrawRectangle(g_editImage, g_rectangles[i][0], g_rectangles[i][1]);
  10. ? ? ? ? }
  11. ? ? }
  12. }
  13. void OnDrawRectangleMouseEvent(int event, int x, int y, int flags, void* userdata)
  14. {
  15. ? ? if (event == cv::EVENT_LBUTTONDOWN)
  16. ? ? {
  17. ? ? ? ? if (g_editPoints.size() > 0)
  18. ? ? ? ? {
  19. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));
  20. ? ? ? ? ? ? g_rectangles.push_back(g_editPoints);
  21. ? ? ? ? ? ? RedrawAllRectangles();
  22. ? ? ? ? ? ? g_editPoints.clear();
  23. ? ? ? ? ? ? imshow("image", g_editImage);
  24. ? ? ? ? }
  25. ? ? ? ? else
  26. ? ? ? ? {
  27. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));//第一个点
  28. ? ? ? ? }
  29. ? ? }
  30. ? ? else if (event == cv::EVENT_MOUSEMOVE)
  31. ? ? {
  32. ? ? ? ? if (g_editPoints.size() > 0)
  33. ? ? ? ? {
  34. ? ? ? ? ? ? RedrawAllRectangles();
  35. ? ? ? ? ? ? DrawRectangle(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y));
  36. ? ? ? ? ? ? imshow("image", g_editImage);
  37. ? ? ? ? }
  38. ? ? }
  39. }

5、绘制多边形轮廓

绘制多边形的函数cv::polylines,有两种形式,其中一个定义如下

  1. void polylines(InputOutputArray img, InputArrayOfArrays pts,bool isClosed, const Scalar& color,int thickness = 1, int lineType = LINE_8, int shift = 0 );
  2. /*
  3. @param img 图像
  4. @param pts 多边形坐标数组
  5. @param isClosed 是否绘制闭合多边形
  6. @param color 线颜色
  7. @param thickness 线宽
  8. @param lineType 线类型
  9. @param shift ?点坐标位偏移
  10. */

这里的pts是一个2维数组,表示多个多边形,以下分别实现绘制多个多边形和单个多边形的函数

  1. void DrawMultiPolys(const cv::Mat& destImg, const std::vector<std::vector<cv::Point>>& points, bool bClose)
  2. {
  3. ? ? cv::polylines(destImg, points, bClose, CV_RGB(255, 0, 0), 1);
  4. }
  5. void DrawOnePoly(const cv::Mat& destImg, const std::vector<cv::Point>& points,bool bClose)
  6. {
  7. ? ? if (points.size() >= 2)
  8. ? ? {
  9. ? ? ? ? std::vector<std::vector<cv::Point>> polyPoints;
  10. ? ? ? ? polyPoints.push_back(points);
  11. ? ? ? ? DrawMultiPolys(destImg,polyPoints,bClose);
  12. ? ? }
  13. }

以下示例实现在鼠标多次点击的位置绘制多边形,main函数与画直线一样,将鼠标事件回调改成OnDrawPolyMouseEvent

  1. std::vector<std::vector<cv::Point>> g_polys;//所有的多边形
  2. void RedrawAllPolys()
  3. {
  4. ? ? g_originImage.copyTo(g_editImage);//恢复背景图像
  5. ? ? DrawMultiPolys(g_editImage,g_polys,true);
  6. }
  7. void OnDrawPolyMouseEvent(int event, int x, int y, int flags, void* userdata)
  8. {
  9. ? ? if (event == cv::EVENT_LBUTTONDOWN)
  10. ? ? {
  11. ? ? ? ? if (g_editPoints.size() > 0)
  12. ? ? ? ? {
  13. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));
  14. ? ? ? ? ? ? RedrawAllPolys();
  15. ? ? ? ? ? ? DrawOnePoly(g_editImage, g_editPoints, false);//正在绘制的多边形要单独画,而且不能闭合
  16. ? ? ? ? ? ? imshow("image", g_editImage);
  17. ? ? ? ? }
  18. ? ? ? ? else
  19. ? ? ? ? {
  20. ? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));//第一个点
  21. ? ? ? ? }
  22. ? ? }
  23. ? ? else if (event == cv::EVENT_MOUSEMOVE)
  24. ? ? {
  25. ? ? ? ? if (g_editPoints.size() > 0)
  26. ? ? ? ? {
  27. ? ? ? ? ? ? RedrawAllPolys();
  28. ? ? ? ? ? ? DrawOnePoly(g_editImage,g_editPoints,false);//正在绘制的多边形要单独画,而且不能闭合
  29. ? ? ? ? ? ? DrawLine(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y));//绘制一根到鼠标位置的直线
  30. ? ? ? ? ? ? imshow("image", g_editImage);
  31. ? ? ? ? }
  32. ? ? }
  33. ? ? else if (event == cv::EVENT_RBUTTONDOWN)
  34. ? ? {
  35. ? ? ? ? //右键按下结束多边形绘制,加入到g_polys
  36. ? ? ? ? g_polys.push_back(g_editPoints);
  37. ? ? ? ? RedrawAllPolys();
  38. ? ? ? ? g_editPoints.clear();
  39. ? ? ? ? cv::imshow("image", g_editImage);
  40. ? ? }
  41. }

6、绘制填充多边形

绘制填充多边形函数cv::fillPoly,有两种形式,其中一个定义如下

  1. void fillPoly(InputOutputArray img, InputArrayOfArrays pts,const Scalar& color, int lineType = LINE_8, int shift = 0,Point offset = Point() );
  2. /*
  3. @param img 图像
  4. @param pts 多边形坐标数组
  5. @param color 线颜色
  6. @param lineType 线类型
  7. @param shift ?点坐标位偏移
  8. @param offset 所有多边形点的偏移
  9. */

绘制填充多边形与绘制多边形轮廓差不多,只要将polylines换成fillpoly

  1. void DrawMultiPolys(const cv::Mat& destImg, const std::vector<std::vector<cv::Point>>& points)
  2. {
  3. ? ? cv::fillPoly(destImg, points,CV_RGB(255, 0, 0));
  4. }
  5. void DrawOnePoly(const cv::Mat& destImg, const std::vector<cv::Point>& points)
  6. {
  7. ? ? if (points.size() >= 2)
  8. ? ? {
  9. ? ? ? ? std::vector<std::vector<cv::Point>> polyPoints;
  10. ? ? ? ? polyPoints.push_back(points);
  11. ? ? ? ? DrawMultiPolys(destImg,polyPoints);
  12. ? ? }
  13. }

如果将上面的所有功能以一定方式组合起来,就可以在图像上绘制多种形状图形并保存了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号