一、背景

  在OpenCV中,可以画圆、线、矩形、椭圆和多边形,但并不能画出虚线,现希望通过OpenCV已有的函数画出由点或线组成的虚线。

cv::circle() // 画一个简单圆
cv::clipLine() // 判断一条直线是否在给定的矩形内
cv::ellipse() // 画一个椭圆,可以倾斜,或者只有部分圆弧
cv::ellipse2Poly() // 计算一个近似椭圆的多边形
cv::fillConvexPoly() // 画一个填充的简单多边形
cv::fillPoly() // 画一个填充的任意多边形
cv::line() // 画一条简单直线
cv::rectangle() // 画一个简单矩形
cv::polyLines() // 画多重折线

二、实现

注意事项:
1、OpenCV虽然没有画点的函数,但可通过cv::circle()实现,只要半径够短,线够厚,一个实心圆可看成一个点。
2、创建空白图片时,其图片类型应选择CV_32FC3CV_64FC3。存储像素的位数越多,画出的斜线越直。
3、两个点画出一条线,故使用g_firstg_last两个Point来存储所画的线。画线主要分为水平线、垂直线和倾斜线三种情况。倾斜线表示方法如下,设置每个点或线的间隔,已知 x x x即可求出 y y y,由此可确定每个点或每条线的坐标。
y − y 1 y 2 − y 1 = x − x 1 x 2 − x 1 ⇒ y = ( y 2 − y 1 ) ( x 2 − x 1 ) ∗ ( x − x 1 ) + y 1 \frac{y-y_1}{y_2-y_1} = \frac{x-x_1}{x_2-x_1} \Rightarrow y = \frac{(y2-y1)}{(x2-x1)}*(x-x1)+y1 y2​−y1​y−y1​​=x2​−x1​x−x1​​⇒y=(x2−x1)(y2−y1)​∗(x−x1)+y1

操作方法:
1、运行程序,在空白图片上按下鼠标左键并移动,鼠标左键释放时即可画出一条虚线。鼠标右键点击可擦掉已画出的虚线。
2、程序包含2种模式,模式1画出由点组成的虚线,模式2画出由线组成的虚线。鼠标默认使用模式1,可通过键盘输入12选择不同模式。键盘输入除12的键会自动退出程序。

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;Point2f g_first, g_last; // 线的起点和终点// 画由点组成的虚线
void draw_dotted_line1(Mat img, Point2f p1, Point2f p2, Scalar color, int thickness)
{float n = 15; //虚点间隔float w = p2.x - p1.x, h = p2.y - p1.y;float l = sqrtf(w * w + h * h);int m = l / n;n = l / m; // 矫正虚点间隔,使虚点数为整数circle(img, p1, 1, color, thickness); // 画起点circle(img, p2, 1, color, thickness); // 画终点// 画中间点if (p1.y == p2.y) // 水平线:y = m{float x1 = min(p1.x, p2.x);float x2 = max(p1.x, p2.x);for (float x = x1 + n; x < x2; x = x + n)circle(img, Point2f(x, p1.y), 1, color, thickness);}else if (p1.x == p2.x) // 垂直线, x = m{float y1 = min(p1.y, p2.y);float y2 = max(p1.y, p2.y);for (float y = y1 + n; y < y2; y = y + n)circle(img, Point2f(p1.x, y), 1, color, thickness);}else // 倾斜线,与x轴、y轴都不垂直或平行{// 直线方程的两点式:(y-y1)/(y2-y1)=(x-x1)/(x2-x1) -> y = (y2-y1)*(x-x1)/(x2-x1)+y1float m = n * abs(w) / l;float k = h / w;float x1 = min(p1.x, p2.x);float x2 = max(p1.x, p2.x);for (float x = x1 + m; x < x2; x = x + m)circle(img, Point2f(x, k * (x - p1.x) + p1.y), 1, color, thickness);}
}// 画由线组成的虚线
void draw_dotted_line2(Mat img, Point2f p1, Point2f p2, Scalar color, int thickness)
{float n = 15; //线长度float w = p2.x - p1.x, h = p2.y - p1.y;float l = sqrtf(w * w + h * h);// 矫正线长度,使线个数为奇数int m = l / n;m = m % 2 ? m : m + 1;n = l / m;circle(img, p1, 1, color, thickness); // 画起点circle(img, p2, 1, color, thickness); // 画终点// 画中间点if (p1.y == p2.y) //水平线:y = m{float x1 = min(p1.x, p2.x);float x2 = max(p1.x, p2.x);for (float x = x1, n1 = 2 * n; x < x2; x = x + n1)line(img, Point2f(x, p1.y), Point2f(x + n, p1.y), color, thickness);}else if (p1.x == p2.x) //垂直线, x = m{float y1 = min(p1.y, p2.y);float y2 = max(p1.y, p2.y);for (float y = y1, n1 = 2 * n; y < y2; y = y + n1)line(img, Point2f(p1.x, y), Point2f(p1.x, y + n), color, thickness);}else // 倾斜线,与x轴、y轴都不垂直或平行{// 直线方程的两点式:(y-y1)/(y2-y1)=(x-x1)/(x2-x1) -> y = (y2-y1)*(x-x1)/(x2-x1)+y1float n1 = n * abs(w) / l;float k = h / w;float x1 = min(p1.x, p2.x);float x2 = max(p1.x, p2.x);for (float x = x1, n2 = 2 * n1; x < x2; x = x + n2){Point p3 = Point2f(x, k * (x - p1.x) + p1.y);Point p4 = Point2f(x + n1, k * (x + n1 - p1.x) + p1.y);line(img, p3, p4, color, thickness);}}
}// 矫正坐标
void correct(Point2f &p, const Point2f &p1, const Point2f &p2)
{if (p.x < p1.x)p.x = p1.x;else if (p.x > p2.x)p.x = p2.x;if (p.y < p1.y)p.y = p1.y;else if (p.y > p2.y)p.y = p2.y;
}// 鼠标回调函数
void mouse_callback(int event, int x, int y, int flags, void *param)
{static size_t i = 0; // 鼠标操作步骤的标识switch (event){case cv::EVENT_LBUTTONDOWN: // 鼠标左键点击if (i == 0){g_first = Point2f(x, y);        // 保存线的起点g_last = Point2f(x + 1, y + 1); // 保存线的终点i = 1;}break;case cv::EVENT_MOUSEMOVE: // 鼠标移动if (i == 1)g_last = Point2f(x, y); // 刷新线的终点break;case cv::EVENT_LBUTTONUP: // 鼠标左键释放if (i == 1)i = 2; // 不再画线break;case cv::EVENT_RBUTTONDOWN: // 鼠标右键点击,清除内容i = 0;g_first = Point2f(0, 0);g_last = Point2f(0, 0);break;default:break;}
}int main()
{const int w = 800, h = 600;const string window_name = "image";Mat image_original = cv::Mat(h, w, CV_32FC3, cv::Scalar(255, 255, 255)); // 选择CV_32FC3,画出的斜线更直cv::imshow(window_name, image_original);cv::setMouseCallback(window_name, mouse_callback); // 鼠标函数char flag = '1';while (true){Mat img = image_original.clone(); // 克隆图片,方便在同一张图片上多次画线correct(g_last, Point2f(0, 0), Point2f(img.cols, img.rows));if (flag == '1')draw_dotted_line1(img, g_first, g_last, Scalar(0, 255, 0), 2); // 模式1画由点组成的虚线elsedraw_dotted_line2(img, g_first, g_last, Scalar(0, 255, 0), 2); // 模式2画由线组成的虚线imshow(window_name, img);char c = waitKey(1); // 获取键盘输入的字符if (c == '1' || c == '2')flag = c;else if (c > 0) // 若不按'1'或'2',按其它字符键会自动退出。break;}return 0;
}

运行结果:

学习OpenCV3:在空白图片上画虚线相关推荐

  1. Matlab 在图片上画虚线矩形框

    matlab在图片上rectangle详解 Rectangle 属性 矩形的外观和行为 矩形属性控制矩形对象的外观和行为.通过更改属性值,您可以修改矩形的特定方面.使用圆点表示法查询和设置属性. h ...

  2. C#图片处理之:在图片上画直线

    在图片上画直线比画框更简单.线形的控制还是通过对Pen的设置来实现的.         /**//// <summary>         /// 在图片上画线         /// & ...

  3. python中怎样在图片上画线段_python 实现PIL模块在图片画线写字

    图片上画线条 import sys from PIL import Image,ImageDraw im = Image.open("th.png") draw = ImageDr ...

  4. html中矩形坐标,js怎么根据坐标在图片上画出矩形框?

    如图本地上传的图片,并点击获取到这个图片里每个地方的坐标,根据4个角坐标在图片上画出矩形框,该怎么画?大神支招. 我图片是显示在div里的,是不是应该用canvas显示图片? 代码: Document ...

  5. 网页在图片上画长方形和直线,并且能控制和编辑

    网页在图片上画长方形和直线,并且能控制和编辑 网页在图片上画长方形和直线,并且能控制和编辑 网页在图片上画长方形和直线,并且能控制和编辑 工作上用到了 在一张图片上画正方形和直线.并且可以控制和编辑 ...

  6. python怎么在散点图上画圆圈_Python如何在图片上画一个实心圆

    有时候我们需要对图片进行标记操作,即在原图的基础上进行画出一些图案,这里给出画一个实心圆的相关方法,基于Python. 工具/原料 win10系统64位 winPython集成软件 方法/步骤 1 集 ...

  7. Python 在图片上画点、圆和矩形实例

    1.在图片上画点.圆 import cv2 img = cv2.imread(img_path) # 读取图片cv2.circle(img,(100,100),20,(0,0,255),-1) # c ...

  8. 用python的opencv库在图片上画出蓝底黑字的文本框

    以下是使用Python的OpenCV库实现在图片上绘制的示例代码: import cv2# 读入图片 img = cv2.imread('example.jpg')# 在图片上绘制红色矩形框 cv2. ...

  9. html5在图片中加链接,JavaScript、html5、canvas实现图片上画超链接

    本文主要为大家详细介绍了JavaScript html5 canvas实现图片上画超链接,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能帮助到大家. 1. html 2. javascrip ...

最新文章

  1. mysql数据库 web asp.net,使用基于asp.net web的应用程序的mysql数据库
  2. UVa1153 Keep The Customer Satisfied(贪心)
  3. 欧拉降幂及其扩展欧拉降幂
  4. 仿明日方舟网页html,《明日方舟》干员列表实现
  5. 每日一题题目26:选择排序(冒泡排序改进版)
  6. java正则表达式的进阶使用20180912
  7. Atitit 互联网技术公司防爆指南技术规范标准流程 30个危险物品
  8. 转:有效沟通的四种工具
  9. 怎样区别7290喷壳机与原壳黑莓手机,里面有详图
  10. iPhone中国移动收不到彩信,设置方法?
  11. Designing Data-Intensive Applications翻译
  12. 开发8年的老Android才知道,赶紧收藏备战金三银四!
  13. redisclient工具个人理解
  14. route命令添加永久路由
  15. 爱了爱了!java是不是比前端难
  16. bootstrap 精美_基于Bootstrap 4和Vuejs构建的精美资源
  17. android 绘制控件,Android_开发_Day29_自己绘制控件
  18. 开发工具:推荐一款非常好用的SSH客户端WindTerm
  19. Windows平台 常用开发工具下载
  20. Java遗传算法(GA)简单例子

热门文章

  1. python高分书籍推荐_如果只能推荐一本 Python 书,我一定 Pick 它
  2. 【单片机】Android手机USB外接STM32单片机通过ADB实现投屏反向控制的功能
  3. 美国计算机生物学大学,美国计算机大学排名
  4. MySQL自学笔记详细版(从安装到入门)
  5. 图片太大怎么办?压缩图帮你几秒搞定在线图片压缩
  6. 最新字节跳动面试题与岗位层级,绩效考核制度介绍
  7. 【已解决】Win10 更新失败的问题【错误代码为0x80070003】
  8. 神箭手 美国亚马逊_亚马逊会摧毁美国的购物中心吗?还是会拯救它们?
  9. 计算机操作系统 - 内存管理
  10. Erlang 下载安装