万用表数据导出变化曲线图——pycharm实现视频数据导出变化曲线图

news2025/2/26 1:59:35

万用表数据导出变化曲线图——pycharm实现视频数据导出变化曲线图

  • 一、效果展示
  • 二、环境配置
  • 三、代码构思
  • 四、代码展示
  • 五、代码、python环境包链接

一、效果展示

图1.1 效果展示
(左图:万用表视频截图;右图:表中数据变化曲线图)

二、环境配置

软件:PyCharm 2021.1.3 (Professional Edition)

python环境包:放在文章结尾文件链接,其中 .yaml 文件

三、代码构思

Created with Raphaël 2.3.0 Start 预备工作:拍摄一段万用表视频 预备工作:裁剪视频、读取视频每秒帧数 代码1:将视频按帧数截屏至某文件夹下 代码2:ocr 截屏文件夹下所有文件 代码3:正则表达式筛选截图中数字数据,并修正数据 代码4:绘图 End

四、代码展示

# functions.py
import cv2
import os
import glob

# video to img
def extract_frames(video_path, output_folder, interval):
    cap = cv2.VideoCapture(video_path)
    frame_count = 0
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        if frame_count % interval == 0:
            output_path = f"{output_folder}/frame_{interval}_{frame_count // interval}.jpg"
            cv2.imwrite(output_path, frame)
        frame_count += 1
    cap.release()


# 计数文件夹里的文件个数
def count_files_in_directory(directory):
    return len([f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))])


# 删除文件夹下的图片
def del_imgs(folder_path):
    # 定义要删除的图片文件夹路径
    # 获取文件夹中所有图片文件的路径
    image_files = glob.glob(os.path.join(folder_path, '*.jpg')) + glob.glob(os.path.join(folder_path, '*.png'))

    # 遍历所有图片文件并删除
    for image_file in image_files:
        os.remove(image_file)

# img_to_plot.py
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import MultipleLocator


def wyb_plot(Real_time_value, Maximum, Average, Minimum, fps, title, x_scale=2, y_scale=0.500):
    x = [i for i in range(len(Real_time_value))]
    plt.figure(dpi=200)

    x_major_locator = MultipleLocator(x_scale)
    # 把x轴的刻度间隔设置为2,并存在变量里
    y_major_locator = MultipleLocator(y_scale)
    # 把y轴的刻度间隔设置为0.0500,并存在变量里
    ax = plt.gca()
    # ax为两条坐标轴的实例
    ax.xaxis.set_major_locator(x_major_locator)
    # 把x轴的主刻度设置为1的倍数
    ax.yaxis.set_major_locator(y_major_locator)
    # 把y轴的主刻度设置为10的倍数

    # # 绘制柱状图
    # y = Real_time_value
    # plt.bar(x, y)

    # 绘制曲线图
    plt.plot(x, Real_time_value, label='Real_time_value')
    plt.plot(x, Maximum, label='Maximum')
    plt.plot(x, Average, label='Average')
    plt.plot(x, Minimum, label='Minimum')

    # 绘制曲线图,并标出最大值和最小值
    max_y = np.max(Real_time_value)
    min_y = np.min(Real_time_value)
    max_index = np.argmax(Real_time_value)
    min_index = np.argmin(Real_time_value)
    plt.annotate("(%s,%s)" % (x[max_index], max_y), xy=(x[max_index], max_y), xytext=(x[max_index], max_y + 0.5),
                 textcoords='offset points',
                 color='red')
    plt.savefig('wyb_plot.png')
    plt.annotate("(%s,%s)" % (x[min_index], min_y), xy=(x[min_index], min_y), xytext=(x[min_index], min_y - 0.5),
                 textcoords='offset points',
                 color='green')

    max_y = np.max(Maximum)
    min_y = np.min(Maximum)
    max_index = np.argmax(Maximum)
    min_index = np.argmin(Maximum)
    plt.annotate("(%s,%s)" % (x[max_index], max_y), xy=(x[max_index], max_y), xytext=(x[max_index], max_y + 0.5),
                 textcoords='offset points',
                 color='red')
    plt.savefig('wyb_plot.png')
    plt.annotate("(%s,%s)" % (x[min_index], min_y), xy=(x[min_index], min_y), xytext=(x[min_index], min_y - 0.5),
                 textcoords='offset points',
                 color='green')

    max_y = np.max(Average)
    min_y = np.min(Average)
    max_index = np.argmax(Average)
    min_index = np.argmin(Average)
    plt.annotate("(%s,%s)" % (x[max_index], max_y), xy=(x[max_index], max_y), xytext=(x[max_index], max_y + 0.5),
                 textcoords='offset points',
                 color='red')
    plt.savefig('wyb_plot.png')
    plt.annotate("(%s,%s)" % (x[min_index], min_y), xy=(x[min_index], min_y), xytext=(x[min_index], min_y - 0.5),
                 textcoords='offset points',
                 color='green')

    max_y = np.max(Minimum)
    min_y = np.min(Minimum)
    max_index = np.argmax(Average)
    min_index = np.argmin(Average)
    plt.annotate("(%s,%s)" % (x[max_index], max_y), xy=(x[max_index], max_y), xytext=(x[max_index], max_y + 0.5),
                 textcoords='offset points',
                 color='red')
    plt.savefig('wyb_plot.png')
    plt.annotate("(%s,%s)" % (x[min_index], min_y), xy=(x[min_index], min_y), xytext=(x[min_index], min_y - 0.5),
                 textcoords='offset points',
                 color='green')

    plt.xlabel('x/'+str(fps)+"fps")
    plt.ylabel('y/A')
    plt.title(title)
    plt.legend()
    plt.savefig('wyb_plot.png')
    # plt.show()

# main.py
import functions
import numpy as np
import ocr_imgs
import img_to_plot

# 用户告知!/ Users informed!
print("Welcome to use wyb_project!")
print("Please place the video under the video folder")

# 逻辑判断 / logical judgment
video_path_lj = int(input("Whether to set the video_path( default video_path = ./video/wybdata.mp4)(1/0): "))
interval_lj = int(input("Whether to set the interval( default screenshot / fps = 30)(1/0): "))

video_path = "./video/wybdata.mp4"
output_folder = "./img"
# 输入 video name / Enter your video name
if video_path_lj:
    vi_name = input("Enter a video name(mind add suffix): ")
    video_path = "./video/" + vi_name

# screenshot/fps
interval = 30  # 默认每隔30帧截取一张图片
if interval_lj:
    interval = int(input("screenshot / fps: "))

# screenshot
extract_frames = functions.extract_frames
extract_frames(video_path, output_folder, interval)

# 计数文件夹里的文件个数
directory = output_folder
count_files_in_directory = functions.count_files_in_directory
file_count = count_files_in_directory(directory) - 1

# 定义要遍历的文件夹路径
folder_path = output_folder
# 每帧计数
frame_count = 0
# 数据数组
data_str = []
# 丢失数组
data_lost = []

# ocr imgs
ocr_imgs = ocr_imgs.ocr_imgs(file_count, folder_path, interval, data_str, data_lost)

data_float = [float(x) for x in data_str]

# 绘图
# 定义万用表绘制的数据列表
Real_time_value = []
Maximum = []
Average = []
Minimum = []

for i in range(len(data_float)):
    if i % 4 == 0:
        Real_time_value.append(data_float[i])
        Maximum.append(data_float[i + 1])
        Average.append(data_float[i + 2])
        Minimum.append(data_float[i + 3])

fps = interval  # 30
Real_time_value = np.array(Real_time_value)
Maximum = np.array(Maximum)
Average = np.array(Average)
Minimum = np.array(Minimum)

x_y_lj = int(input("Whether to set x and y axis scale( default x_scale=2, y_scale=0.500)(1/0): "))
if x_y_lj:
    x_scale = float(input("input x axis scale: "))
    y_scale = float(input("input y axis scale: "))

title_lj = int(input("Whether to set the title of plot ( default \"wyb_plot\")(1/0): "))
if title_lj:
    title = input("enter a title for plot: ")

title = "wyb_plot"
wyb_plot = img_to_plot.wyb_plot(Real_time_value, Maximum, Average, Minimum, fps, title, x_scale=2, y_scale=0.500)

img_del_lj = int(input("Whether to delete imgs of imgs folder( default delete)(1/0): "))
if img_del_lj:
    folder_path = output_folder
    del_imgs  = functions.del_imgs(folder_path)

# ocr_imgs.py
from cnocr import CnOcr
import re


def ocr_imgs(file_count, folder_path, interval, data_str, data_lost):
    # 遍历文件夹文件(图片),进行文字识别
    for frame_count in range(file_count):
        img_fp = f"{folder_path}/frame_{interval}_{frame_count}.jpg"
        ocr = CnOcr()  # 所有参数都使用默认值
        out_list = ocr.ocr(img_fp)
        data_list = []
        for dict in out_list:
            text = dict.get('text')
            match = re.search(r'[0-9Oo][.,][0-9Oo][0-9Oo][0-9Oo][0-9Oo]|[Q][0-9Oo][0-9Oo][0-9Oo][0-9Oo]', text)  # 正则化匹配
            if match:
                result = match.group()
                # print(result)
                # with open('output.txt', 'a') as f:
                #     print(result, file=f)
                result = result.replace('O', '0').replace('o', '0').replace(',', '.')  # 修正数据
                data_list.append(result)
                # with open('output.txt', 'a') as f:
                #     print(result, file=f)
        if len(data_list) % 4 == 0:
            data_str += data_list
        else:
            print("数据丢失," + "frame_" + str(interval) + "_" + str(frame_count) + ".jpg" + "未采集")
            data_lost.append(frame_count)

    # 手动采集图片数据 / manual capture
    man_cap = int(input("Whether manual collection(1/0): "))
    if man_cap:
        for frame in data_lost:
            data_ins = 0
            for i in range(4):
                if i == 0:
                    data_ins = (input("rea: "))
                if i == 1:
                    data_ins = (input("max: "))
                if i == 2:
                    data_ins = (input("ave: "))
                if i == 3:
                    data_ins = (input("min: "))
                data_str.insert((file_count - len(data_list) + 1) * 4 + i, data_ins)

五、代码、python环境包链接

wyb_project https://www.alipan.com/s/dKwQhvHpb4Z 提取码: 6mm1
点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。

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

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

相关文章

宽度优先搜索算法(BFS)

宽度优先搜索算法(BFS)是什么? 宽度优先搜索算法(BFS)(也称为广度优先搜索)主要运用于树、图和矩阵(这三种可以都归类在图中),用于在图中从起始顶点开始逐层…

字节跳动的 SDXL-LIGHTNING : 体验飞一般的文生图

TikTok 的母公司字节跳动推出了最新的文本到图像生成人工智能模型,名为SDXL-Lightning。顾名思义,这个新模型只需很轻量的推理步骤(1,4 或 8 步)即可实现极其快速且高质量的文本到图像生成功能。与原始 SDXL 模型相比&…

嵌入式 Linux 学习

在学习嵌入式 Linux 之前,我们先来了解一下嵌入式 Linux 有哪些东西。 1. 嵌入式 Linux 的组成 嵌入式 Linux 系统,就相当于一套完整的 PC 软件系统。 无论你是 Linux 电脑还是 windows 电脑,它们在软件方面的组成都是类似的。 我们一开电…

.NET高级面试指南专题十六【 装饰器模式介绍,包装对象来包裹原始对象】

装饰器模式(Decorator Pattern)是一种结构型设计模式,用于动态地给对象添加额外的职责,而不改变其原始类的结构。它允许向对象添加行为,而无需生成子类。 实现原理: 装饰器模式通过创建一个包装对象来包裹原…

【数据可视化】动手用matplotlib绘制关联规则网络图

下载文中数据、代码、绘图结果 文章目录 关于数据绘图函数完整可运行的代码运行结果 关于数据 如果想知道本文的关联规则数据是怎么来的,请阅读这篇文章 绘图函数 Python中似乎没有很方便的绘制网络图的函数。 下面是本人自行实现的绘图函数,如果想…

【深度学习笔记】6_9 深度循环神经网络deep-rnn

注:本文为《动手学深度学习》开源内容,部分标注了个人理解,仅为个人学习记录,无抄袭搬运意图 6.9 深度循环神经网络 本章到目前为止介绍的循环神经网络只有一个单向的隐藏层,在深度学习应用里,我们通常会用…

three.js如何实现简易3D机房?(四)点击事件+呼吸灯效果

接上一篇: three.js如何实现简易3D机房?(三)显示信息弹框/标签:http://t.csdnimg.cn/5W2wA 目录 八、点击事件 1.实现效果 2.获取相交点 3.呼吸灯效果 4.添加点击事件 5.问题解决 八、点击事件 1.实现效果 2.…

ChatGPT发不出消息?GPT发不出消息怎么办?

前言 今天发现,很多人的ChatGPT无法发送信息,我就登陆看一下自己的GPT的情况,结果还真的无法发送消息,ChatGPT 无法发送消息,但是能查看历史的对话,不过通过下面的方法解决了。 第一时间先打开官方的网站&a…

Mint_21.3 drawing-area和goocanvas的FB笔记(七)

FreeBASIC gfx 基本 graphics 绘图 8、ScreenControl与屏幕窗口位置设置 FreeBASIC通过自建屏幕窗口摆脱了原来的屏幕模式限制,既然是窗口,在屏幕坐标中就有它的位置。ScreenControl GET_WINDOW_POS x, y 获取窗口左上角的x, y位置;ScreenC…

【REST2SQL】11 基于jwt-go生成token与验证

【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 【REST2SQL】07 GO 操作 Mysql 数据库 【RE…

设计模式学习系列 -- 随记

文章目录 前言 一、设计模式是什么? 二、设计模式的历史 三、为什么以及如何学习设计模式? 四、关于模式的争议 一种针对不完善编程语言的蹩脚解决方案 低效的解决方案 不当使用 五、设计模式分类 总结 前言 最近可能工作生活上的稳定慢慢感觉自己丢失…

掌握 Vue3、Vite 和 SCSS 实现一键换肤的魔法步骤

前言 一个网站的换肤效果算是一个比较常见的功能,尤其是在后台管理系统中,我们几乎都能看到他的身影,这里给大家提供一个实现思路。 搭建项目 vitevue3搭建项目这里就不演示了,vite官网里面讲得很清楚。 注:这里使…

浅析开源内存数据库Fastdb

介绍: Fastdb是免费开源内存数据库,其优秀的性能,和简洁的C代码,让我学习使用过程中收益颇多,但是国内中文相关研究的文章相当稀少,外文我查询相当不便。有兴趣的朋友可以通过以下网站访问:Mai…

java-ssm-jsp基于ssm的冰淇淋在线购买网站

java-ssm-jsp基于ssm的冰淇淋在线购买网站 获取源码——》公主号:计算机专业毕设大全

【STM32】HAL库 CubeMX 教程 --- 通用定时器 TIM2 定时

实验目标: 通过CUbeMXHAL,配置TIM2,1s中断一次,闪烁LED。 一、常用型号的TIM时钟频率 1. STM32F103系列: 所有 TIM 的时钟频率都是72MHz;F103C8不带基本定时器,F103RC及以上才带基本定时器。…

react实战——react旅游网

慕课网react实战 搭建项目问题1.按照官网在index.tsx中引入antd出错?2.typescript中如何使用react-router3.react-router3.1 V63.2 V53.3V6实现私有路由 4.函数式组件接收props参数时定义数据接口?5.使用TypeScript开发react项目:6.要使一个组…

探索stable diffusion的奇妙世界--01

目录 1. 理解prompt提示词: 2. Prompt中的技术参数: 3. Prompt中的Negative提示词: 4. Prompt中的特殊元素: 5. Prompt在stable diffusion中的应用: 6. 作品展示: 在AI艺术领域,stable di…

数据结构——线性表顺序表示详解

目录 1.线性表的类型定义 2.基本操作 3.线性表的存储结构 4.补充 1.元素类型说明 2.数组定义​编辑 3.c语言的内存动态分配 4.c的动态存储分配 5.c中的参数传递 引用类型作参数 6.顺序表基本操作的实现 1.线性表的初始化 代码示例: 2.销毁线性表&…

远程连接Linux系统

图形化、命令行 对于操作系统的使用,有2种使用形式: 图形化页面使用操作系统 图形化:使用操作系统提供的图形化页面,以获得图形化反馈的形式去使用操作系统。 以命令的形式使用操作系统 命令行:使用操作系统提供的各…

腾讯云轻量服务器Windows系统使用IIS实现公网直链访问文件

windows方便所以服务器装的windows系统,windows默认不能分享文件直链,只要用IIS建个站点就行了 先弄一台有公网ip的windows系统服务器打开服务器管理器,添加这个 打开IIS右键添加网站 程序池默认,路径选个文件夹作为网站根目录 …