【工业机器视觉】基于深度学习的水表盘读数识别(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,从基础知识到高…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

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实现分布式…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...