【工业机器视觉】基于深度学习的水表盘读数识别(3-数据标注与转换)
【工业机器视觉】基于深度学习的仪表盘识读(2)-CSDN博客
数据标注
标注扩展
Labelme 和 LabelImg 都是用于创建机器学习和计算机视觉项目所需标注数据的工具。它们都允许用户通过图形界面手动标注图像,但各自有其特点和适用场景。
Labelme
- 开发语言:Python
- 标注类型:Labelme 支持多种标注类型,包括但不限于多边形(polygon)、矩形(rectangle)、线段(line)、点(point)等。它非常适合需要精确标注物体边界的情况,比如在医疗影像、自动驾驶等领域。
- 文件格式:标注结果通常保存为 JSON 文件,其中包含每个标注对象的坐标信息、标签名称等。
- 灵活性:Labelme 提供了插件系统,可以扩展其功能,如支持更多的图像格式或添加自定义的标注类型。
- 跨平台:基于 Python 的 Qt 库构建,可以在 Windows、macOS 和 Linux 上运行。
LabelImg
- 开发语言:Python
- 标注类型:主要支持矩形框(bounding box)标注,适合于目标检测任务。对于需要简单快速地对多个对象进行框选标注的任务来说非常方便。
- 文件格式:标注结果可以保存为 Pascal VOC XML 格式或者 YOLO txt 格式,这两种格式都是目标检测任务中常用的标注文件格式。
- 轻量化:相比于 Labelme,LabelImg 更加轻量化,易于安装和使用,尤其适合初学者。
- 跨平台:同样基于 Python 的 Qt 库,可以在不同操作系统上运行。
安装扩展包:
pip install labelme labelimg
指针区域
使用labelimg进行BOX标注,标签类别:{'area_p', 'p0', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'},p0~p9为最低位x0.001标签类别,area_p为其他高位指针区域标签类别。
示例:
标签文件是VOC XML文件数据,后面再通过脚本转换成YOLO格式数据。
梅花针分割
使用labelme进行实例切割,标签类别:{'pointer', 'circle_area'},pointer是红色梅花针区域,circel_area是刻度圆。
示例:
标签文件是JSON格式文件数据,后面再通过脚本转换成YOLO格式数据。
字轮区域
使用labelimg进行BOX标注,标签类别:{'d0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'd10', 'd11', 'd12', 'd13', 'd14', 'd15', 'd16', 'd17', 'd18', 'd19'},d0~9表示数字刚好在字轮窗口中心位置,也就是非过渡状态,d10~19表示各个数字的过渡状态。
示例:
标签文件是VOC XML文件数据,后面再通过脚本转换成YOLO格式数据。
数据划分
在深度学习中,训练集和验证集是用于模型开发过程中的两个重要数据集。它们各自扮演着不同的角色,确保最终模型的性能和泛化能力。
训练集(Training Set)
- 用途:训练集主要用于训练模型。即,在这个数据集上调整模型的权重或参数,使模型能够学习到数据中的特征和模式。
- 特点:通常包含大量带标签的数据样本,这些数据样本应该尽可能地代表实际应用环境中的数据分布。
- 影响:如果训练集的质量不高(如数据量不足、标注不准确或偏差),可能会导致模型过拟合或欠拟合,从而影响其性能。
验证集(Validation Set)
- 用途:验证集用于在训练过程中评估模型的表现,帮助选择模型的最佳配置(例如,超参数调优)。它提供了一个独立于训练集的反馈机制,用以监测模型是否开始过拟合训练数据。
- 特点:与训练集类似,验证集也应该是有代表性的,并且它的标签也是已知的。但是,它不应该被用来直接更新模型参数;相反,它是用来决定何时停止训练(早停法)或选择最佳模型架构/超参数。
- 影响:通过验证集可以有效防止过拟合,确保模型不仅在训练数据上表现良好,而且在未见过的数据上也能保持良好的性能。
注意事项
- 划分比例:常见的是将数据划分为70%训练集和30%验证集,或者采用交叉验证的方法来更充分利用有限的数据。具体的比例可以根据实际情况调整。
- 测试集:除了训练集和验证集之外,有时还会有一个测试集(Test Set),用于最终评估模型的真实性能。测试集在整个训练和验证过程中都应该保持完全独立,直到最后评估时才使用。
正确管理和使用训练集和验证集对于构建一个有效的深度学习模型至关重要。这有助于确保模型不仅能很好地适应训练数据,还能对新数据做出准确预测。
数据划分代码:
import argparse
import os
import random
from os import getcwd# root = getcwd() + '\\my_datas\\pointer-seg\\'
root = getcwd() + '\\my_datas\\detect-pointer\\'
# root = getcwd() + '\\my_datas\\detect-digit\\'
parser = argparse.ArgumentParser()parser.add_argument('--img_path', default='IMAGES', type=str,help='input images file path')
parser.add_argument('--txt_path', default='TXT_LABELS', type=str,help='output txt label path')
opt = parser.parse_args()trainval_percent = 1.0
train_percent = 0.9
imgfilepath = root + opt.img_path
txtsavepath = root + opt.txt_path
total_img = os.listdir(imgfilepath)
if not os.path.exists(txtsavepath):os.makedirs(txtsavepath)num = len(total_img)
list_index = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list_index, tv)
train = random.sample(trainval, tr)try:os.remove(txtsavepath + '/trainval.txt')os.remove(txtsavepath + '/train.txt')os.remove(txtsavepath + '/valid.txt')
except:pass
file_trainval = open(txtsavepath + '/trainval.txt', 'w')
file_train = open(txtsavepath + '/train.txt', 'w')
file_val = open(txtsavepath + '/valid.txt', 'w')for i in list_index:name = total_img[i] + '\n'if i in trainval:file_trainval.write(imgfilepath + '/' + name)if i in train:file_train.write(imgfilepath + '/' + name)else:file_val.write(imgfilepath + '/' + name)file_trainval.close()
file_train.close()
file_val.close()
IMAGES为所有需要学习的数据图片目录
数据转换
VOC XML 转 YOLO
import os
import shutil
import xml.etree.ElementTree as ET
from tqdm import tqdmsets = ['train', 'valid']
project_name = 'detect-pointer'
classes = ['area_p', 'p0', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9']
# project_name = 'detect-digit'
# classes = ['d0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9',
# 'd10', 'd11', 'd12', 'd13', 'd14', 'd15', 'd16', 'd17', 'd18', 'd19']abs_path = os.getcwd()def convert(size, box):dw = 1. / (size[0])dh = 1. / (size[1])x = (box[0] + box[1]) / 2.0 - 1y = (box[2] + box[3]) / 2.0 - 1w = box[1] - box[0]h = box[3] - box[2]x = x * dww = w * dwy = y * dhh = h * dhreturn x, y, w, hdef convert_annotation(image_id, image_set):in_file = open(r'my_datas\%s\ANNOTATIONS\%s.xml' % (project_name, image_id), encoding='UTF-8')out_file = open(r'my_datas\%s\%s\labels\%s.txt' % (project_name, image_set, image_id), 'w')tree = ET.parse(in_file)root = tree.getroot()size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):difficult = obj.find('difficult').textcls = obj.find('name').textif cls not in classes or int(difficult) == 1:continuecls_id = classes.index(cls)xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))b1, b2, b3, b4 = b# 标注越界修正if b2 > w:b2 = wif b4 > h:b4 = hb = (b1, b2, b3, b4)bb = convert((w, h), b)out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')# 删除文件夹中所有文件
def del_all_file(path):for root, dirs, files in os.walk(path):for f in files:os.remove(os.path.join(root, f))del_all_file(f'my_datas\\{project_name}\\train\images')
print('train\images delete success.')
del_all_file(f'my_datas\\{project_name}\\train\labels')
print('train\labels delete success.')
del_all_file(f'my_datas\\{project_name}\\valid\images')
print('valid\images delete success.')
del_all_file(f'my_datas\\{project_name}\\valid\labels')
print('valid\labels delete success.')for image_set in sets:image_files = open(r'my_datas\%s\TXT_LABELS\%s.txt' % (project_name, image_set)).read().strip().split()for image_file in tqdm(image_files):image_id = os.path.basename(image_file)[:-4]convert_annotation(image_id, image_set)shutil.copyfile(image_file, r'my_datas\%s\%s\images\%s' % (project_name,image_set, os.path.basename(image_file)))
JSON 转 YOLO
import json
import os
import shutil
from tqdm import tqdmimport numpy as npproject_name = 'pointer-seg'
sets = ['train', 'valid']
classes = ['pointer', 'circle_area']
abs_path = os.getcwd()def convert(size, box):dw = 1. / (size[0])dh = 1. / (size[1])x = (box[0] + box[1]) / 2.0 - 1y = (box[2] + box[3]) / 2.0 - 1w = box[1] - box[0]h = box[3] - box[2]x = x * dww = w * dwy = y * dhh = h * dhreturn x, y, w, hdef pointer_distance(x1, y1, x2, y2):dis = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)return disdef json_to_yolo(path):with open(path, encoding='UTF-8') as f:labelme_data = json.load(f)width = labelme_data["imageWidth"]height = labelme_data["imageHeight"]yolo_lines = []for shape in labelme_data["shapes"]:if shape['shape_type'] == 'polygon':# 多边形label = shape["label"]points = shape["points"]class_idx = classes.index(label)txt_string = f"{class_idx} "for x, y in points:x /= widthy /= heighttxt_string += f"{x} {y} "yolo_lines.append(txt_string.strip() + "\n")elif shape['shape_type'] == 'circle':# 圆label = shape["label"]points = shape["points"]class_idx = classes.index(label)txt_string = f"{class_idx} "# 圆心a, b = points[0]# 计算半径r = pointer_distance(a, b, points[1][0], points[1][1])# 生成一些在圆上的点X = np.linspace(a - r, a + r - 1, 15)f = lambda x: np.sqrt(r ** 2 - (x - a) ** 2) + by1 = f(X)y2 = 2 * b - y1c_points = []for i, x in enumerate(X):c_points.append([x, y1[i]])c_points.append([x, y2[i]])for x, y in c_points:x /= widthy /= heighttxt_string += f"{x} {y} "yolo_lines.append(txt_string.strip() + "\n")return yolo_linesdef convert_annotation(image_id, image_set):lines = json_to_yolo(r'my_datas\%s\ANNOTATIONS\%s.json' % (project_name, image_id))with open(r'my_datas\%s\%s\labels\%s.txt' % (project_name, image_set, image_id), 'w') as out_file:out_file.writelines(lines)def del_all_file(path):for root, dirs, files in os.walk(path):for f in files:os.remove(os.path.join(root, f))del_all_file(f'my_datas\\{project_name}\\train\images')
print('train\images delete success.')
del_all_file(f'my_datas\\{project_name}\\train\labels')
print('train\labels delete success.')
del_all_file(f'my_datas\\{project_name}\\valid\images')
print('valid\images delete success.')
del_all_file(f'my_datas\\{project_name}\\valid\labels')
print('valid\labels delete success.')for image_set in sets:image_files = open(r'my_datas\%s\TXT_LABELS\%s.txt' % (project_name, image_set)).read().strip().split()for image_file in tqdm(image_files):image_id = os.path.basename(image_file)[:-4]convert_annotation(image_id, image_set)shutil.copyfile(image_file, r'my_datas\%s\%s\images\%s' % (project_name,image_set, os.path.basename(image_file)))
完整目录结构:
至此,用于深度学习所需的所有训练、验证数据已准备好,下一篇开始基于Utralytics YOLO系列进行训练和预测。
【工业机器视觉】基于深度学习的仪表盘识读(读数识别)(4)-CSDN博客
相关文章:

【工业机器视觉】基于深度学习的水表盘读数识别(3-数据标注与转换)
【工业机器视觉】基于深度学习的仪表盘识读(2)-CSDN博客 数据标注 标注扩展 Labelme 和 LabelImg 都是用于创建机器学习和计算机视觉项目所需标注数据的工具。它们都允许用户通过图形界面手动标注图像,但各自有其特点和适用场景。 Labelme…...

python数据分析之爬虫基础:selenium详细讲解
目录 1、selenium介绍 2、selenium的作用: 3、配置浏览器驱动环境及selenium安装 4、selenium基本语法 4.1、selenium元素的定位 4.2、selenium元素的信息 4.3、selenium元素的交互 5、Phantomjs介绍 6、chrome handless模式 1、selenium介绍 (1…...

Tips--解决esptool经pyinstaller打包后无法使用的问题
esptool打包后失效解决方法 问题1原因解决方法问题2原因解决方法 问题1 esptool经过pyinstaller打包成exe后,提示错误:Stub flasher JSON file for esp32 not found 原因 pyinstaller在进行esptool打包的时候,通常不用讲Stub flaser Json文…...

Apache DolphinScheduler 限制秒级别的定时调度
背景 Apache DolphinScheduler 定时任务配置采用的 7 位 Crontab 表达式,分别对应秒、分、时、月天、月、周天、年。 在团队日常开发工作中,工作流的定时调度一般不会细化到秒级别。但历史上出现过因配置的疏忽大意而产生故障时间,如应该配…...
Oracle 数据库创建用户并分配只读的权限
引言 在 Oracle 数据库的日常运维和开发过程中,用户管理是确保数据安全与访问控制的关键环节。通过合理创建用户并分配适当的权限,可以有效防止未授权的访问和操作。本文将详细介绍如何在 Oracle 数据库中: 创建新用户并设置复杂密码。授予…...

2个GitHub上最近比较火的Java开源项目
1. SpringBlade 微服务架构 标题 SpringBlade 微服务架构 摘要 SpringBlade 是一个由商业级项目升级优化而来的微服务架构,采用Spring Boot 3.2、Spring Cloud 2023等核心技术构建,遵循阿里巴巴编码规范,提供基于React和Vue的两个前端框架&am…...
【jvm】为什么要有GC
目录 1. 自动内存管理2. 提升程序稳定性3. 优化性能4. 跨平台能力5. 分代回收策略 1. 自动内存管理 1.JVM中的GC机制负责自动管理内存,这意味着开发人员不需要手动分配和释放内存。2.这一特性大大简化了Java程序的内存管理,降低了内存泄漏和内存溢出等问…...

【Rhino】【Python】根据contour创建地形mesh
将surface生成open curve封闭 #codingutf-8 import rhinoscriptsyntax as rs import mathdef adjust_endpoints():# 获取指定图层中的所有曲线all_objects rs.ObjectsByLayer("Level 19")if not all_objects:print("在Level 19图层中未找到对象")return#…...

蓝桥杯软件赛系列---lesson1
🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 我们今天会再开一个系列,那就是蓝桥杯系列,我们会从最基础的开始讲起,大家想要备战明年蓝桥杯的,让我们一起加油。 工具安装 DevC…...
NanoLog起步笔记-1
nonolog起步笔记-1 背景与上下文写在前面Nanolog与一般的实时log的异同现代log的一般特性Nanolog的选择 背景与上下文 因为工作中用到了NanoLog。有必要研究一下。 前段时间研究了许多内容,以为写了比较详实的笔记,今天找了找,不仅笔记没找到…...

汽车车牌标记支持YOLO,COCO,VOC三种格式标记,4000张图片的数据集
本数据集支持YOLO,COCO,VOC三种格式标记汽车车牌,无论是新能源汽车还是油车都能识别标记,该数据集一共包含4000张图片 数据集分割 4000总图像数 训练组 70% 2800图片 有效集 20% 800图片 测…...
leetcode33.搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..…...

Ansible自动化运维(三)playbook剧本详解
Ansible自动化运维这部分我将会分为五个部分来为大家讲解 (一)介绍、无密钥登录、安装部署、设置主机清单 (二)Ansible 中的 ad-hoc 模式 模块详解(15)个 (三)Playbook 模式详解 …...

通过PS和Unity制作2D动画之二:IK的使用
一、IK的概念 IK:Inverse Kinematics,反向动力学。 (1)正向动力学 在骨骼动画中,构建骨骼的方法被称为正向动力学。它的表现形式是:子骨骼(关节)的位置根据父骨骼(关节…...

图像边缘检测原理和常用检测算子及MATLAB实现
一、边缘和边缘检测的概念 图像边缘是指图像中灰度值发生急剧变化的地方,这些变化通常对应于图像中物体的轮廓、边界或纹理的突变处。在数字图像处理中,边缘是图像的一个重要特征,它包含了关于物体形状、位置和大小等关键信息。 边缘检测是数…...
企业经营数据分析系统:提升决策能力的利器
搭建企业经营数据分析系统是当今企业绕不开的话题,企业想要在竞争激烈的市场当中突围而出,需要对于企业内部的各种数据了然于胸,同时对于外部的数据也有敏锐的把握能力,因此企业构建自身的经营性数据分析系统就显得尤其重要。作为…...

【49】AndroidStudio构建其他人开发的Android项目
(1)做Android软件开发,通常会看一些其他人开发的项目源码,当将这些项目的源码通过git clone到本地之后,用AndroidStudio进行打开时,通常会遇到一些环境配置的问题。本文即用来记录在构建他人开发项目源代码这一过程中遇到的一些常…...
Oracle 数据库中SERIALLY_REUSABLE包是一种特殊的包类型
1、SERIALLY_REUSABLE 包概述 在 Oracle 数据库中,SERIALLY_REUSABLE包是一种特殊的包类型。这种包的目的是为了更有效地利用内存,特别是在高并发环境下。当一个会话调用SERIALLY_REUSABLE包中的过程或函数时,该包的状态(包括变量…...

css基础记录
基础 选择器 复合选择器 后代选择器 div p {}; 类似如上,找到div中所有的后代,注意是所有的后代 子代选择器 > div > a 只选择div的儿子中有a的 并集选择器 用逗号,分隔 p,div,span,h1 { … } 一般一行写一个 CSS元素显示模式 分为块元素,行内元素 块元素 特点…...
Python后端 -- 万字长文全面解析Django框架
自从2005年诞生以来,Django因其“开发速度快、安全性高”的特点迅速成为许多开发者的首选。无论是小型的个人项目,还是大型的企业应用,Django都能游刃有余地满足需求。我们将从Django的基础知识带你全面掌握Django,从基础知识到高…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...