OpenCV绘制图形功能

OpenCV绘制图形功能

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

1、绘制直线

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

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的红色直线定义为一个函数

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键保存图像。

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.webp");     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.webp", g_editImage);         }         key = cv::waitKey(0);     }     return 0; } 2、绘制圆

绘制圆的函数cv::circle

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

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

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,有两种形式,其中一个定义如下

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

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

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,有两种形式,其中一个定义如下

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

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

 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,有两种形式,其中一个定义如下

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维数组,表示多个多边形,以下分别实现绘制多个多边形和单个多边形的函数

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

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,有两种形式,其中一个定义如下

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

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

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

推荐阅读

    excel怎么用乘法函数

    excel怎么用乘法函数,乘法,函数,哪个,excel乘法函数怎么用?1、首先用鼠标选中要计算的单元格。2、然后选中单元格后点击左上方工具栏的fx公

    iPad的手势功能iPad4手势的使用教程

    iPad的手势功能iPad4手势的使用教程,,可能有很多朋友刚刚接触过iPad,他们对手势的功能和用法知之不多。以下是对iPad手势使用的简单介绍。

    excel中乘法函数是什么?

    excel中乘法函数是什么?,乘法,函数,什么,打开表格,在C1单元格中输入“=A1*B1”乘法公式。以此类推到多个单元。1、A1*B1=C1的Excel乘法公式

    标准差excel用什么函数?

    标准差excel用什么函数?,函数,标准,什么,在数据单元格的下方输入l标准差公式函数公式“=STDEVPA(C2:C6)”。按下回车,求出标准公差值。详细

    金立s10快捷键|金立s10功能键设置

    金立s10快捷键|金立s10功能键设置,,金立s10功能键设置1、首先来说如何隐藏应用。这个功能可以说是非常的完美,当然要实现这个功能要结合金

    监控外网设置|外网监控的基本功能

    监控外网设置|外网监控的基本功能,,1. 外网监控的基本功能首先,要在Internet中找到一个设备,必须有一个公网的IP地址,如果连接外网的出口没有

    2010年底DIY硬件总结和安装参考

    2010年底DIY硬件总结和安装参考,,它似乎只是一眨眼的功夫从过去的最后一眼。看看现在的岗位似乎就在昨天,但看看当年的内容是真的走了,如果

    vivo网络设置代码|vivo功能代码

    vivo网络设置代码|vivo功能代码,,1. vivo功能代码代码是*#558#1.首先在手机桌面里找到电话。2.在拨号键盘里输入*#558#3.这时候就进入了手