学习OpenCV3:在空白图片上画虚线
一、背景
在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_32FC3
或CV_64FC3
。存储像素的位数越多,画出的斜线越直。
3、两个点画出一条线,故使用g_first
和g_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−y1y−y1=x2−x1x−x1⇒y=(x2−x1)(y2−y1)∗(x−x1)+y1
操作方法:
1、运行程序,在空白图片上按下鼠标左键并移动,鼠标左键释放时即可画出一条虚线。鼠标右键点击可擦掉已画出的虚线。
2、程序包含2种模式,模式1画出由点组成的虚线,模式2画出由线组成的虚线。鼠标默认使用模式1,可通过键盘输入1
或2
选择不同模式。键盘输入除1
或2
的键会自动退出程序。
#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:在空白图片上画虚线相关推荐
- Matlab 在图片上画虚线矩形框
matlab在图片上rectangle详解 Rectangle 属性 矩形的外观和行为 矩形属性控制矩形对象的外观和行为.通过更改属性值,您可以修改矩形的特定方面.使用圆点表示法查询和设置属性. h ...
- C#图片处理之:在图片上画直线
在图片上画直线比画框更简单.线形的控制还是通过对Pen的设置来实现的. /**//// <summary> /// 在图片上画线 /// & ...
- python中怎样在图片上画线段_python 实现PIL模块在图片画线写字
图片上画线条 import sys from PIL import Image,ImageDraw im = Image.open("th.png") draw = ImageDr ...
- html中矩形坐标,js怎么根据坐标在图片上画出矩形框?
如图本地上传的图片,并点击获取到这个图片里每个地方的坐标,根据4个角坐标在图片上画出矩形框,该怎么画?大神支招. 我图片是显示在div里的,是不是应该用canvas显示图片? 代码: Document ...
- 网页在图片上画长方形和直线,并且能控制和编辑
网页在图片上画长方形和直线,并且能控制和编辑 网页在图片上画长方形和直线,并且能控制和编辑 网页在图片上画长方形和直线,并且能控制和编辑 工作上用到了 在一张图片上画正方形和直线.并且可以控制和编辑 ...
- python怎么在散点图上画圆圈_Python如何在图片上画一个实心圆
有时候我们需要对图片进行标记操作,即在原图的基础上进行画出一些图案,这里给出画一个实心圆的相关方法,基于Python. 工具/原料 win10系统64位 winPython集成软件 方法/步骤 1 集 ...
- Python 在图片上画点、圆和矩形实例
1.在图片上画点.圆 import cv2 img = cv2.imread(img_path) # 读取图片cv2.circle(img,(100,100),20,(0,0,255),-1) # c ...
- 用python的opencv库在图片上画出蓝底黑字的文本框
以下是使用Python的OpenCV库实现在图片上绘制的示例代码: import cv2# 读入图片 img = cv2.imread('example.jpg')# 在图片上绘制红色矩形框 cv2. ...
- html5在图片中加链接,JavaScript、html5、canvas实现图片上画超链接
本文主要为大家详细介绍了JavaScript html5 canvas实现图片上画超链接,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能帮助到大家. 1. html 2. javascrip ...
最新文章
- mysql数据库 web asp.net,使用基于asp.net web的应用程序的mysql数据库
- UVa1153 Keep The Customer Satisfied(贪心)
- 欧拉降幂及其扩展欧拉降幂
- 仿明日方舟网页html,《明日方舟》干员列表实现
- 每日一题题目26:选择排序(冒泡排序改进版)
- java正则表达式的进阶使用20180912
- Atitit 互联网技术公司防爆指南技术规范标准流程 30个危险物品
- 转:有效沟通的四种工具
- 怎样区别7290喷壳机与原壳黑莓手机,里面有详图
- iPhone中国移动收不到彩信,设置方法?
- Designing Data-Intensive Applications翻译
- 开发8年的老Android才知道,赶紧收藏备战金三银四!
- redisclient工具个人理解
- route命令添加永久路由
- 爱了爱了!java是不是比前端难
- bootstrap 精美_基于Bootstrap 4和Vuejs构建的精美资源
- android 绘制控件,Android_开发_Day29_自己绘制控件
- 开发工具:推荐一款非常好用的SSH客户端WindTerm
- Windows平台 常用开发工具下载
- Java遗传算法(GA)简单例子