day4 - 使用图像绘制动态时钟

news2024/9/22 11:32:52

本期的主要内容是利用OpenCV中包含的绘图函数,例如绘制线段、绘制矩形、绘制圆形等来绘制一个动态时钟的表盘。

完成本期内容,你可以:

  • 掌握OpenCV常见的绘图函数

  • 学会使用绘图函数绘制简单的图像

若要运行案例代码,你需要有:

  • 操作系统:Ubuntu 16 以上 或者 Windows10

  • 工具软件:VScode 或者其他源码编辑器

  • 硬件环境:无特殊要求

  • 核心库:python 3.6.13, opencv-contrib-python 3.4.11.39,opencv-python 3.4.2.16

点击下载源码


绘制线段

OpenCV 中提供的绘制线段的函数是 cv2.line()。

函数原型: img = cv2.line(img, plt1, plt2, color, thickness);

img为绘制线段后得到的图像。

参数描述如下:

参数描述
plt1线段的起点坐标
plt2线段的终点坐标
color绘制线段的线条颜色
thickness绘制线段时的线条宽度

绘制矩形

OpenCV 中提供的绘制矩形的函数是 cv2.rectangle()。

函数原型:img = cv2.rectangle(img, plt1, plt2, color, thickness);

img为绘制矩形后得到的图像。

参数描述如下:

参数描述
plt1矩形的左上角坐标
plt2矩形的右下角坐标
color绘制矩阵时的线条颜色
thickness绘制矩阵时的线条宽度,当thickness的值为-1时,可以绘制一个实心矩形

绘制圆形

OpenCV中提供的绘制圆形的函数是cv2.circle()。

函数原型:img = cv2.circle(img, center, radius, color, thickness);

img为绘制圆形后得到的图像。

参数描述如下:

参数描述
center圆形的圆心坐标
radius圆形的半径
color绘制圆形时的线条颜色
thickness绘制圆形时的线条宽度,当thickness的值为-1时,可以绘制一个实心圆形

绘制多边形

OpenCV中提供的绘制多边形的函数是cv2.polylines()。

函数原型:img = cv2.polylines(img, pts, isClosed, color, thickness);

img为绘制多边形后得到的图像。

参数描述如下:

参数描述
pts由多边形各个顶点坐标组成的一个列表。
isClosed指示绘制的折线是否闭合的标志。
color绘制多边形时的线条颜色
thickness绘制多边形时的线条宽度

绘制文字

OpenCV 中提供的绘制文字的函数是cv2.putText()。

函数原型:img = cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType,bottomLeftOrigin)

img为绘制文字后得到的图像。

参数描述如下:

参数描述
text要绘制的文本内容
org文字在画布中的左下角坐标
fontFace字体样式
fontScale字体大小
color绘制文字时的线条颜色
thickness绘制文字时的线条宽度
lineType线型
bottomLeftOrigin绘制文字的方向

可选的字体样式,如下:

字体样式含义
cv.FONT_HERSHEY_SIMPLEX正常大小sans-serif字体
cv.FONT_HERSHEY_PLAIN小尺寸sans-serif字体
cv.FONT_HERSHEY_DUPLEX正常大小的sans-serif字体(比FONT_HERSHEY_SIMPLEX更复杂)
cv.FONT_HERSHEY_COMPLEX正常大小serif字体
cv.FONT_HERSHEY_TRIPLEX正常大小serif字体(比FONT_HERSHEY_COMPLEX更复杂)
cv.FONT_HERSHEY_COMPLEX_SMALLFONT_HERSHEY_COMPLEX的简化版本
cv.FONT_HERSHEY_SCRIPT_SIMPLEX手写样式字体
cv.FONT_HERSHEY_SCRIPT_COMPLEX更复杂的FONT_HERSHEY_SCRIPT_SIMPLEX变体
cv.FONT_ITALIC斜体字体

4.5 表盘刻度线

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NkNNqUPt-1684908365737)(image\md_img.png)]

通过观察可以发现,时钟主要由两部分组成,分别是静态表盘和动态表针。整个表盘其实只有3根表针在动,所以可以先画出静态表盘,然后获取系统当前时间,根据时间实时动态绘制3根表针就解决了。

4.5.1 绘制刻度

表盘上只有60条分/秒刻线和12条小时刻线,当然还有表盘的外部轮廓圆,也就是重点在如何画72根线。

前面我们使用OpenCV画直线的时候,需知道直线的起点和终点坐标,那么画72根线就变成了获取72组坐标。

在平面坐标系下,已知半径和角度的话,A点的坐标可以表示为:


$\ x = r \times cos\alpha $ $\ y = r \times sin\alpha $

请添加图片描述

先只考虑将坐标系原点移动到左上角,角度依然是平面坐标系中的逆时针计算,那么新坐标是:

x = r + r ×   c o s α x= r+ r\times\ cos\alpha x=r+r× cosα y = r + r ×   s i n α y =r+r\times\ sin\alpha y=r+r× sinα

对于60条分/秒刻线,刻线间的夹角是360°/60=6°,对于小时刻线,角度是360°/12=30°,这样就得到了72组起点坐标,那怎么得到终点坐标呢?其实同样的原理,用一个同心的小圆来计算得到终点:

  • 角度换算

    接下来算是一个小难点,首先时钟的起始坐标在正常二维坐标系的90°方向,其次时钟跟图像一样,都是顺时针计算角度的,所以三者需要统一下:

请添加图片描述

因对于时钟坐标和图像坐标,时钟0的0°对应图像的270°,时钟15的90°对应图像的360°,时钟30的180°对应图像的450°(270°+180°)…

所以两者之间的关系便是:

计算角度 = 时钟角度+270°
计算角度 = 计算角度 if 计算角度<=360° else 计算角度-360°

具体步骤

1. 创建项目结构

创建项目名为使用OpenCV绘制动态时钟,项目根目录下新建code文件夹储存代码,新建dataset文件夹储存数据,项目结构如下:

使用OpenCV绘制动态时钟                    # 项目名称
├── code                               # 储存代码文件
├── dataset                            # 储存数据文件

注:如项目结构已存在,无需再创建。

2. 创建画布并绘制表盘

  1. code文件夹下创建clock.py文件;
  2. 导入需要用到的模块datetime, opencv, math, numpy
  3. 设置表盘距上下左右的边距,圆心和半径;
  4. 创建一个450*450的画布,并填充为白色;
  5. 画出表盘,线条颜色为黑色,线条宽度为5;
  6. 展示表盘。

代码实现

# 导入所需模块
import cv2
import math
import datetime
import numpy as np
import matplotlib.pyplot as plt

# 设置边距、半径、圆心
margin = 5  # 上下左右边距
radius = 220  # 圆的半径
center = (center_x, center_y) = (225, 225)  # 圆心

# 新建一个画板并填充成白色
img = np.zeros((450, 450, 3), np.uint8)
img[:] = (255, 255, 255)

# 画出圆盘
cv2.circle(img, center, radius, (0, 0, 0), thickness=5)
cv2.imshow('clocking',img)

请添加图片描述

实验效果

3. 绘制表盘分钟刻度线

  1. 计算每一条秒和分刻度线的起点和终点的坐标;
  2. 画出60条秒和分的刻度线,颜色为黑色,线条宽度为2;
  3. 展示表盘。

代码实现

# 绘制表盘刻度线
pt1 = []
# 3. 画出60条秒和分钟的刻线
for i in range(60):
    # 最外部圆,计算A点
    x1 = center_x+(radius-margin)*math.cos(i*6*np.pi/180.0)
    y1 = center_y+(radius-margin)*math.sin(i*6*np.pi/180.0)
    pt1.append((int(x1), int(y1)))

    # 同心小圆,计算B点
    x2 = center_x+(radius-15)*math.cos(i*6*np.pi/180.0)
    y2 = center_y+(radius-15)*math.sin(i*6*np.pi/180.0)

    cv2.line(img, pt1[i], (int(x2), int(y2)), (0, 0, 0), thickness=2)
cv2.imshow('clocking',img)

请添加图片描述

实验效果

4. 绘制表盘小时刻度线

  1. 计算每一条小时刻度线的起点和终点的坐标;
  2. 画出12条小时刻度线,颜色为黑色,线条宽度为5;
  3. 展示表盘。

代码实现

#  画出12条小时的刻线
for i in range(12):
    # 12条小时刻线应该更长一点
    x = center_x+(radius-25)*math.cos(i*30*np.pi/180.0)
    y = center_y+(radius-25)*math.sin(i*30*np.pi/180.0)
    # 这里用到了前面的pt1
    cv2.line(img, pt1[i*5], (int(x), int(y)), (0, 0, 0), thickness=5)
cv2.imshow('clocking',img)

请添加图片描述

实验效果

5. 同步时间并绘制指针

  1. 拷贝表盘;
  2. 获取系统时间,拆分时-分-秒;
  3. 根据系统时间,绘制秒刻度线;
  4. 根据系统时间,绘制分刻度线;
  5. 根据系统时间,绘制小时刻度线;
  6. 添加当前日期文字;
  7. 控制按键输入,当输入‘esc’按键时退出,并销毁窗口

代码实现

#同步时间
while True:
    # 不断拷贝表盘图,才能更新绘制,不然会重叠在一起
    temp = np.copy(img)

    # 获取系统时间,画出动态的时-分-秒三条刻线
    now_time = datetime.datetime.now()
    hour, minute, second = now_time.hour, now_time.minute, now_time.second

    # 画秒刻线
    # OpenCV中的角度是顺时针计算的,所以需要转换下
    sec_angle = second*6+270 if second <= 15 else (second-15)*6
    sec_x = center_x+(radius-margin)*math.cos(sec_angle*np.pi/180.0)
    sec_y = center_y+(radius-margin)*math.sin(sec_angle*np.pi/180.0)
    cv2.line(temp, center, (int(sec_x), int(sec_y)), (203, 222, 166), 2)

    # 画分刻线
    min_angle = minute*6+270 if minute <= 15 else (minute-15)*6
    min_x = center_x+(radius-35)*math.cos(min_angle*np.pi/180.0)
    min_y = center_y+(radius-35)*math.sin(min_angle*np.pi/180.0)
    cv2.line(temp, center, (int(min_x), int(min_y)), (186, 199, 137), 8)

    # 画时刻线
    hour_angle = hour*30+270 if hour <= 3 else (hour-3)*30
    hour_x = center_x+(radius-65)*math.cos(hour_angle*np.pi/180.0)
    hour_y = center_y+(radius-65)*math.sin(hour_angle*np.pi/180.0)
    cv2.line(temp, center, (int(hour_x), int(hour_y)), (169, 198, 26), 15)

    # 添加当前日期文字
    font = cv2.FONT_HERSHEY_SIMPLEX
    time_str = now_time.strftime("%d/%m/%Y")
    cv2.putText(img, time_str, (135, 275), font, 1, (0, 0, 0), 2)

    cv2.imshow('clocking', temp)
    if cv2.waitKey(300) == 27:  # 按下ESC键退出
        break
cv2.destroyAllWindows()

请添加图片描述

实验效果

OpenCV中包含的绘图函数有很多,我们可以通过这些简单图形的组合,在结合一些之前学习的知识可以画出很多好玩的图像。

点击下载源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/564361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux——搭建NTP服务器

1、设置服务器时区 &#xff08;使用外部NTP时间源可不设置&#xff09; 在Linux系统中设置时区可以使用以下命令&#xff1a; 查看当前时区&#xff1a; timedatectl列出所有可用时区&#xff1a; timedatectl list-timezones设置时区&#xff1a; sudo timedatectl set-…

一、尚医通手机登录

文章目录 一、登录需求1、登录效果2、登录需求 二、登录1&#xff0c;搭建service-user模块1.1 搭建service-user模块1.2 修改配置1.3 启动类1.4 配置网关 2、添加用户基础类2.1 添加model2.2 添加Mapper2.3 添加service接口及实现类2.4 添加controller 3、登录api接口3.1 添加…

OpenAI再出新作,AIGC时代,3D建模师的饭碗危险了!

大家好&#xff0c;我是千与千寻&#xff0c;也可以叫我千寻哥&#xff0c;说起来&#xff0c;自从ChatGPT发布之后&#xff0c;我就开始焦虑&#xff0c;担心自己程序员的饭碗会不会哪天就被AIGC取代了。 有人说我是过度焦虑了&#xff0c;但是我总觉有点危机感肯定没有坏处。…

分布式事务解决方案-Seata

分布式事务解决方案-Seata 1.分布式事务问题1.1.本地事务1.2.分布式事务1.3.演示分布式事务问题 2.理论基础2.1.CAP定理2.1.1.一致性2.1.2.可用性2.1.3.分区容错2.1.4.矛盾 2.2.BASE理论2.3.解决分布式事务的思路 3.初识Seata3.1.Seata的架构3.2.部署TC服务3.3.微服务集成Seata…

C++ string类 迭代器 范围for

string类 在C语言当中 &#xff0c;也有字符串&#xff0c;它是以 " \0 " 结尾 的 一些字符的集合&#xff0c;在C的标准库当中还有一些 用于操作 str 类型的库函数&#xff0c;但是&#xff0c;这些函数的功能不是很全面&#xff0c;而且这些操作函数和 str 类型是分…

B2B企业需要什么样的客户体验管理?销售易出手了

导读&#xff1a;如何将类似B2C领域的私域体验延展到B2B领域&#xff1f; “不愿在顾客上花时间带来的结果只有一个&#xff0c;那就是让客户转而寻找值得他们花时间的消费体验。”2012年问世的《体验经济》一书&#xff0c;一语道破客户体验的重要性。 过去&#xff0c;提到体…

PG安装使用walminer插件教程

一、下载源码 https://gitee.com/movead/XLogMiner/tree/walminer_3.0_stable/ 二、编译安装插件 克隆下载源码后&#xff0c;将walminer目录放进pg下的contrib目录中 cd /home/postgres/postgresql-15.3/contrib/将walminer源码目录放进此路径下&#xff0c;进入walminer目…

卷麻了,公司新来的00后测试用例写的比我还好,简直无地自容......

经常看到无论是刚入职场的新人&#xff0c;还是工作了一段时间的老人&#xff0c;都会对编写测试用例感到困扰&#xff1f;例如&#xff1a; 如何编写测试用例&#xff1f; 作为一个测试新人&#xff0c;刚开始接触测试&#xff0c;对于怎么写测试用例很是头疼&#xff0c;无法…

STM32寄存器映射

1. 寄存器基本原理 寄存器是单片机内部一种特殊的内存&#xff0c;可以实现对单片机各个功能的控制&#xff0c;我们编写程序最终就是去控制寄存器 下面的举例平台为STM32F407ZG 1.1 STM32寄存器分类 大类小类说明 内核寄存器 内核相关寄存器 包含R0~R15、xPSR、特殊功能寄…

《幸福关系的7段旅程》

关于作者 本书作者安德鲁∙马歇尔&#xff0c;英国顶尖婚姻咨询机构RELATE的资深专家&#xff0c;拥有 30年丰富的咨询经验&#xff0c;并为《泰晤士报》《观察家》和《星期日快报》撰写专栏文章。已出版19部作品&#xff0c;并被翻译成20种语言。 关于本书 《幸福关系的7段…

SQL查询比较慢,如何进行排查?如何进行SQL优化?

目录 一、开启慢查询日志 二、SQL优化 三、总结 一、开启慢查询日志 SQL慢查询是指执行时间较长的SQL语句&#xff0c;可能导致系统性能下降和响应时间延长。通过以下步骤可以开启慢查询日志记录&#xff1a; #查询是否开启慢查询日志 slow_query_log显示ON说明已开启&#…

广和通携手有人物联网完成5G SUL辅助上行功能验证

近日&#xff0c;广和通5G模组FM650-CN已在商用网络中实现5G SUL上行能力增强&#xff0c;助力有人物联网工业路由器在仿真网络环境中完成SUL辅助上行功能的验证。本次验证成功&#xff0c;意味着FM650-CN已具备SUL辅助上行商用能力&#xff0c;有利于推动更多5G终端支持SUL特性…

es 7 Es分布式基础

目录 复杂特性es已经做了分片副本负载均衡实现 设置分片数副本数 双机器读写 自动横向扩容 Node 节点宕机主节点切换 数据路由 增删改操作 读操作 _bulk 复杂特性es已经做了分片副本负载均衡实现 1.每个索引包含多个分片 设置分片数副本数 双机器读写 自动横向扩容 No…

React | React的CSS方式

✨ 个人主页&#xff1a;CoderHing &#x1f5a5;️ React.js专栏&#xff1a;React的CSS方式 &#x1f64b;‍♂️ 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f4ab; 系列专栏&#xff1a;吊打面试官系列 16天学会Vue 11天学会React Node专栏 &#x…

Axure教程—多色折线图(中继器)

本文将教大家如何用AXURE中的中继器制作多色折线图 一、效果介绍 如图&#xff1a; 预览地址&#xff1a;https://xpdm3g.axshare.com 下载地址&#xff1a;https://download.csdn.net/download/weixin_43516258/87814320 二、功能介绍 简单填写中继器内容即可动态显示值样…

AppJoint2-2023再看安卓组件化框架

零、什么是组件化 为了避免一些小伙伴一脸懵的进来&#xff0c;又一脸懵的出去&#xff0c;我先简单的说一下什么是组件化。 开发程序时&#xff0c;我们都希望功能间的耦合度尽可能的低&#xff0c;这样的好处是&#xff1a;便于并行开发、代码易于维护、出问题时也好定位。…

抖音seo矩阵系统源码开发开源型私有化部署方案

抖音SEO矩阵系统是基于抖音平台的搜索引擎优化技术的一种系统&#xff0c;其主要作用是通过一系列的技术手段&#xff0c;提高抖音视频的曝光和排名&#xff0c;使其获得更多的流量和粉丝。在本文中&#xff0c;我们将介绍抖音SEO矩阵系统的开发技术&#xff0c;包括系统设计、…

map reduce实现累加器

需求&#xff1a;数组长度为100&#xff0c;每一项为对应下标&#xff0c;累加求和。 切题思路&#xff1a; 1.如何声明一个长度为100的数组&#xff1f;答&#xff1a;new Array(100) 2.数组每一项如何比前一项1 答&#xff1a;map(item,index)index为数组下标&#xff0c;…

企业推行OKR的必要条件

今天我们的话题是“OKR在企业落地执行,有哪些必要条件&#xff1f;” 对于有落地 OKR 经验的人可能更深有感触&#xff0c;OKR理解起来容易&#xff0c;但落地起来却困难重重&#xff0c;常言道“万事开头难”&#xff0c;那接下来我们就先从落地 OKR 的先决条件开始说起吧。 …

我的创作纪念日,成为创作者的第512天

机缘 从事编程岗一有将近4年的时光了&#xff0c;但正在开始总结写博客还是一年前&#xff0c;是在百度搜素资料了解到的CSDN开发者社区。在CSDN认识了很多技术大牛&#xff0c;他们的文章记录了他们的学习路径&#xff0c;看到他们从小白一步一步成长为大牛&#xff0c;这才下…