当前位置: 首页 > news >正文

自动标注工具 Autolabelimg

原理简介~~

对于数据量较大的数据集,先对其中一部分图片打标签,Autolabelimg利用已标注好的图片进行训练,并利用训练得到的权重对其余数据进行自动标注,然后保存为xml文件。

一、下载yolov5v6.1

https://github.com/ultralytics/yolov5

并对已标注的数据集进行训练,得到权重best.pt

二、将detect_auto.py文件放入yolov5根目录下

import sys
from utils.torch_utils import select_device
from models.common import DetectMultiBackend
from utils.datasets import *
import torch
from utils.general import (check_img_size, non_max_suppression, scale_coords)
from tkinter import *
from tkinter import filedialog
import natsort
# FILE = Path(__file__).resolve()
# ROOT = FILE.parents[0]  # YOLOv5 root directory
# if str(ROOT) not in sys.path:
#     sys.path.append(str(ROOT))  # add ROOT to PATH
# ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relativeimport os
from os import getcwd
from xml.etree import ElementTree as ETclass Detector():def __init__(self):self.objectList = []self.weights = r""  # 可去官方下载v5 6.0的预训练权重模型self.dnn = Falseself.data = r""  # 选择你的配置文件(一般为.yaml)self.device = select_device(device='0')self.half = self.device.type != 'cpu'  # 半精度化self.predefined_classes = []self.imgdir = r""  # 你需要标注的图片文件夹self.outdir = r""  # 你需要保存的xml文件夹self.detect_class = r""  # 你需要自动标注的类型self.root_window = Noneself.flag = False@torch.no_grad()def run(self,frame,model,device,half=False,img_size=None,augment=False,visualize=False,max_det=1000):if img_size is None:img_size = [640, 640]img0 = framestride, names, pt, jit, onnx, engine = model.stride, model.names, model.pt, model.jit, model.onnx, model.engineimg_size = check_img_size(img_size, s=stride)# Halfhalf &= (pt or jit or engine) and device.type != 'cpu'  # half precision only supported by PyTorch on CUDAif pt or jit:model.model.half() if half else model.model.float()img = letterbox(img0, auto=True, new_shape=img_size, stride=32)[0]img = img.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGBimg = np.ascontiguousarray(img)# model.warmup(imgsz=(1, 3, *img_size), half=half)  # warmupimg = torch.from_numpy(img).to(device)img = img.half() if half else img.float()  # uint8 to fp16/32img /= 255  # 0 - 255 to 0.0 - 1.0if len(img.shape) == 3:img = img[None]  # expand for batch dimpred = model(img, augment=augment, visualize=visualize)pred = non_max_suppression(pred, max_det=max_det)for i, det in enumerate(pred):if det is not None and len(det):det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape).round()info_list = []for *xyxy, conf, cls in reversed(det):xyxy = torch.tensor(xyxy).view(-1).tolist()info = [xyxy[0], xyxy[1], xyxy[2], xyxy[3], int(cls)]info_list.append(info)return info_listelse:return Nonedef create_annotation(self, xn):global annotationtree = ET.ElementTree()tree.parse(xn)annotation = tree.getroot()# 遍历xml里面每个object的值如果相同就不插入def traverse_object(self, AnotPath):tree = ET.ElementTree(file=AnotPath)root = tree.getroot()ObjectSet = root.findall('object')for Object in ObjectSet:ObjName = Object.find('name').textBndBox = Object.find('bndbox')x1 = int(BndBox.find('xmin').text)y1 = int(BndBox.find('ymin').text)x2 = int(BndBox.find('xmax').text)y2 = int(BndBox.find('ymax').text)self.objectList.append([x1, y1, x2, y2, ObjName])# 定义一个创建一级分支object的函数def create_object(self, root, objl):  # 参数依次,树根,xmin,ymin,xmax,ymax# 创建一级分支object_object = ET.SubElement(root, 'object')# 创建二级分支name = ET.SubElement(_object, 'name')# print(obj_name)name.text = str(objl[4])pose = ET.SubElement(_object, 'pose')pose.text = 'Unspecified'truncated = ET.SubElement(_object, 'truncated')truncated.text = '0'difficult = ET.SubElement(_object, 'difficult')difficult.text = '0'# 创建bndboxbndbox = ET.SubElement(_object, 'bndbox')xmin = ET.SubElement(bndbox, 'xmin')xmin.text = '%s' % objl[0]ymin = ET.SubElement(bndbox, 'ymin')ymin.text = '%s' % objl[1]xmax = ET.SubElement(bndbox, 'xmax')xmax.text = '%s' % objl[2]ymax = ET.SubElement(bndbox, 'ymax')ymax.text = '%s' % objl[3]# 创建xml文件的函数def create_tree(self, image_name, h, w, imgdir):global annotation# 创建树根annotationannotation = ET.Element('annotation')# 创建一级分支folderfolder = ET.SubElement(annotation, 'folder')# 添加folder标签内容folder.text = (imgdir)# 创建一级分支filenamefilename = ET.SubElement(annotation, 'filename')filename.text = image_name# 创建一级分支pathpath = ET.SubElement(annotation, 'path')# path.text = getcwd() + '\{}\{}'.format(imgdir, image_name)  # 用于返回当前工作目录path.text ='{}/{}'.format(imgdir, image_name)  # 用于返回当前工作目录# 创建一级分支sourcesource = ET.SubElement(annotation, 'source')# 创建source下的二级分支databasedatabase = ET.SubElement(source, 'database')database.text = 'Unknown'# 创建一级分支sizesize = ET.SubElement(annotation, 'size')# 创建size下的二级分支图像的宽、高及depthwidth = ET.SubElement(size, 'width')width.text = str(w)height = ET.SubElement(size, 'height')height.text = str(h)depth = ET.SubElement(size, 'depth')depth.text = '3'# 创建一级分支segmentedsegmented = ET.SubElement(annotation, 'segmented')segmented.text = '0'def pretty_xml(self, element, indent, newline, level=0):  # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行if element:  # 判断element是否有子元素if (element.text is None) or element.text.isspace():  # 如果element的text没有内容element.text = newline + indent * (level + 1)else:element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)# else:  # 此处两行如果把注释去掉,Element的text也会另起一行# element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * leveltemp = list(element)  # 将element转成listfor subelement in temp:if temp.index(subelement) < (len(temp) - 1):  # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致subelement.tail = newline + indent * (level + 1)else:  # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个subelement.tail = newline + indent * levelself.pretty_xml(subelement, indent, newline, level=level + 1)  # 对子元素进行递归操作def work(self):with open(self.detect_class, "r") as f:  # 打开文件for line in f.readlines():line = line.strip('\n')  # 去掉列表中每一个元素的换行符self.predefined_classes.append(line)model = DetectMultiBackend(self.weights, device=self.device, dnn=self.dnn, data=self.data)model.to(self.device).eval()names = model.module.names if hasattr(model, 'module') else model.namesIMAGES_LIST = os.listdir(self.imgdir)for image_name in natsort.natsorted(IMAGES_LIST):# print(image_name)# 判断后缀只处理图片文件if image_name.endswith(('.jpg', '.png', '.jpeg', '.bmp')):image = cv2.imread(os.path.join(self.imgdir, image_name))if image is None:print(image_name+"图像为空请删除")continuefile_tail = os.path.splitext(image_name)[1]coordinates_list = self.run(image, model, self.device, self.half)(h, w) = image.shape[:2]# xml_name = ('.\{}\{}.xml'.format(outdir, image_name.strip('.jpg')))xml_name = ('{}\{}.xml'.format(self.outdir, image_name.strip('.jpg')))if (os.path.exists(xml_name)):self.create_annotation(xml_name)self.traverse_object(xml_name)else:self.create_tree(image_name, h, w, self.imgdir)if coordinates_list:print(image_name+"已标注完成")for coordinate in coordinates_list:label_id = coordinate[4]if (self.predefined_classes.count(names[label_id]) > 0):object_information = [int(coordinate[0]), int(coordinate[1]), int(coordinate[2]),int(coordinate[3]), names[label_id]]if (self.objectList.count(object_information) == 0):self.create_object(annotation, object_information)self.objectList = []# 将树模型写入xml文件tree = ET.ElementTree(annotation)root = tree.getroot()self.pretty_xml(root, '\t', '\n')# tree.write('.\{}\{}.xml'.format(outdir, image_name.strip('.jpg')), encoding='utf-8')tree.write('{}\{}.xml'.format(self.outdir, image_name.strip(file_tail)), encoding='utf-8')else:print(image_name)# 客户端def client(self):def creatWindow():self.root_window.destroy()window()def judge(str):if (str):text = "你已选择" + strelse:text = "你还未选择文件夹,请选择"return textdef test01():self.imgdir = r""self.imgdir += filedialog.askdirectory()creatWindow()def test02():self.outdir = r""self.outdir += filedialog.askdirectory()creatWindow()def test03():self.data = r""self.data += filedialog.askopenfilename()creatWindow()def test04():self.weights = r""self.weights += filedialog.askopenfilename()creatWindow()def test05():self.detect_class = r""self.detect_class += filedialog.askopenfilename()creatWindow()def tes06():self.work()self.flag=TruecreatWindow()def window():self.root_window = Tk()self.root_window.title("")screenWidth = self.root_window.winfo_screenwidth()  # 获取显示区域的宽度screenHeight = self.root_window.winfo_screenheight()  # 获取显示区域的高度tk_width = 500  # 设定窗口宽度tk_height = 400  # 设定窗口高度tk_left = int((screenWidth - tk_width) / 2)tk_top = int((screenHeight - tk_width) / 2)self.root_window.geometry('%dx%d+%d+%d' % (tk_width, tk_height, tk_left, tk_top))self.root_window.minsize(tk_width, tk_height)  # 最小尺寸self.root_window.maxsize(tk_width, tk_height)  # 最大尺寸self.root_window.resizable(width=False, height=False)btn_1 = Button(self.root_window, text='请选择你要标注的图片文件夹', command=test01,height=0)btn_1.place(x=169, y=40, anchor='w')text = judge(self.imgdir)text_label = Label(self.root_window, text=text)text_label.place(x=160, y=70, anchor='w')btn_2 = Button(self.root_window, text='请选择你要保存的xml文件夹(.xml)', command=test02,height=0)btn_2.place(x=169, y=100, anchor='w')text = judge(self.outdir)text_label = Label(self.root_window, text=text)text_label.place(x=160, y=130, anchor='w')btn_3 = Button(self.root_window, text='请选择你的配置文件(.yaml)', command=test03,height=0)btn_3.place(x=169, y=160, anchor='w')text = judge(self.data)text_label = Label(self.root_window, text=text)text_label.place(x=160, y=190, anchor='w')# if(self.outdir and self.imgdir and self.data):btn_4 = Button(self.root_window, text='请选择使用的模型(.pt)', command=test04,height=0)btn_4.place(x=169, y=220, anchor='w')text = judge(self.weights)text_label = Label(self.root_window, text=text)text_label.place(x=160, y=250, anchor='w')btn_5 = Button(self.root_window, text='请选择需要自动标注的类别文件(.txt)', command=test05,height=0)btn_5.place(x=169, y=280, anchor='w')text = judge(self.detect_class)text_label = Label(self.root_window, text=text)text_label.place(x=160, y=310, anchor='w')btn_6 = Button(self.root_window, text='开始自动标注', command=tes06,height=0)btn_6.place(x=169, y=340, anchor='w')if (self.flag):text = "标注完成"else:text = "等待标注"text_label = Label(self.root_window, text=text)text_label.place(x=160, y=370, anchor='w')self.root_window.mainloop()window()if __name__ == '__main__':detector = Detector()detector.client()

三、运行detect_auto.py文件

  • 建议将要标注的图片文件和标注完的.xml文件放在同一文件夹下,这样方便使用labelimg查看标注效果;
  • 配置文件即为训练时data文件夹下对应的.yaml文件;
  • 使用的模型为训练好的权重文件(best.pt);
  • 在根目录下创建class.txt文件,里面为数据集所包含的类别;

  • 点击开始自动标注; 

 

tips:自动标注的质量不是特别高,如果对标注质量有要求的话还需手动进行调整

报错处理:改动utils/torch_utils.py文件中第55行如下

 

reference

【解放双手YOLOv5 6.0自动标注(已开源)】 https://www.bilibili.com/video/BV1TZ4y1S76W/?p=2&share_source=copy_web&vd_source=95705b32f23f70b32dfa1721628d5874 

相关文章:

自动标注工具 Autolabelimg

原理简介~~ 对于数据量较大的数据集&#xff0c;先对其中一部分图片打标签&#xff0c;Autolabelimg利用已标注好的图片进行训练&#xff0c;并利用训练得到的权重对其余数据进行自动标注&#xff0c;然后保存为xml文件。 一、下载yolov5v6.1 https://github.com/ultralytic…...

2023-03-20干活

transformer复现 from torch.utils.data import Dataset,DataLoader import numpy as np import torch import torch.nn as nn import os import time import math from tqdm import tqdmdef get_data(path,numNone):all_text []all_label []with open(path,"r",e…...

Java 注解(详细学习笔记)

注解 注解英文为Annotation Annotation是JDK5引入的新的技术 Annotation的作用&#xff1a; 不是程序本身&#xff0c;可以对程序做出解释可以被其他程序&#xff08;比如编译器&#xff09;读取。 Annotation的格式&#xff1a; 注解是以注解名在代码中存在的&#xff0c;还…...

LeetCode:35. 搜索插入位置

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340;算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 一、&#x1f331;35. 搜索插入位置 题目描述&#xff1a;给定一个排序数组和一个目标值&…...

菜鸟刷题Day2

菜鸟刷题Day2 一.判定是否为字符重排&#xff1a;字符重排 描述 给定两个由小写字母组成的字符串 s1 和 s2&#xff0c;请编写一个程序&#xff0c;确定其中一个字符串的字符重新排列后&#xff0c;能否变成另一个字符串。 解题思路&#xff1a; 这题思路与昨天最后两道类似&…...

Selenium基础篇之不打开浏览器运行

文章目录前言一、场景二、设计1.引入库2.引入浏览器配置3.设置无头模式4.启动浏览器实例&#xff0c;添加配置信息5.访问质量分地址6.隐式等待5秒7.定位到输入框8.输入博文地址9.定位到查询按钮10.点击查询按钮11.定位到查询结果模块div12.打印结果13.结束webdriver进程三、结果…...

【数据结构初阶】栈与队列笔试题

前言在我们学习了栈和队列之后&#xff0c;今天来通过几道练习题来巩固一下我们的知识。题目一 用栈实现队列题目链接&#xff1a;232. 用栈实现队列 - 力扣&#xff08;Leetcode&#xff09;这道题难度不是很大&#xff0c;重要的是我们对结构认识的考察&#xff0c;由于这篇文…...

【Linux入门篇】操作系统安装、网络配置

目录 &#x1f341;Linux详解 &#x1f342;1.操作系统 &#x1f342;2.操作系统组成 &#x1f342;3.操作系统历史 &#x1f342;4.常见的Linux系统 &#x1f342;5.centos7下载 &#x1f342;6.安装centos7 &#x1f341;linux初始化配置 &#x1f343;1.虚拟机系统安装后操作…...

Selenium:找不到对应的网页元素?常见的一些坑

目录 1. 用Xpath查找数据时无法直接获取节点属性 2. 使用了WebDriverWait以后仍然无法找到元素 2.1. 分辨率原因 2.2. 需要滚动页面 2.3. 由于其他元素的遮挡 1. 用Xpath查找数据时无法直接获取节点属性 通常在我们使用xpath时&#xff0c;可以使用class的方式直接获取节…...

flex布局优化(两端对齐,从左至右)

文章目录前言方式一 nth-child方式二 gap属性方式三 设置margin左右两边为负值总结前言 flex布局是前端常用的布局方式之一&#xff0c;但在使用过程中&#xff0c;我们总是感觉不太方便&#xff0c;因为日常开发中&#xff0c;大多数时候&#xff0c;我们想要的效果是这样的 …...

【Django 网页Web开发】03. 初识Django(保姆级图文)

目录1. 命令行创建与pycharm创建的区别2. 项目结构信息2.1 项目结构2.2 项目app结构2.3 快速查看项目结构树3. 创建并注册app3.1 创建app3.2 注册app4. 编写URL与视图的对应关系5. 编写视图文件6. 启动项目7. 写多个页面8. templates模板的使用8.1 编写html文件8.3 导入html文件…...

KubeSphere All in one安装配置手册

KubeSphere All in one安装配置手册 1. 初始化 1.1 配置apt源 # vi /etc/apt/sources.list deb https://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse deb-src https://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiversedeb…...

Spring Boot 核心配置文件

Spring Boot 核心配置文件1、application.properties2、application.yml使用建议3、常用配置项服务器配置数据库配置日志配置其他配置4、配置文件的加载顺序5、配置文件的占位符6、配置文件的动态刷新7、配置文件的属性分组定义属性分组绑定属性分组使用属性分组总结Spring Boo…...

个人小站折腾后记

个人小站折腾后记 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c;目前在某…...

WebService简单入门

1. JAX-WS发布WebService 创建web工程 创建simple包&#xff0c;和server、client两个子包。正常情况下server和client应该是两个项目&#xff0c;这里我们只是演示效果&#xff0c;所以简化写到一个项目中&#xff1a; 1.1 创建服务类Server package simple.server;import ja…...

「Vue面试题」vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?

文章目录一、是什么二、如何做接口权限路由权限控制菜单权限方案一方案二按钮权限方案一方案二小结参考文章一、是什么 权限是对特定资源的访问许可&#xff0c;所谓权限控制&#xff0c;也就是确保用户只能访问到被分配的资源 而前端权限归根结底是请求的发起权&#xff0c;…...

Docker部署springcloud项目(清晰明了)

概述 最近在想做个cloud项目,gitee上找了个模板项目&#xff0c;后端使用到 Nacos、Gateway、Security等技术&#xff0c;需要到 Docker 容器部署&#xff0c;在此总结一下&#xff0c;若有不足之处&#xff0c;望大佬们可以指出。 什么是 Docker Docker 使用 Google 公司推…...

搭建SFTP服务安全共享文件,实现在外远程访问「内网穿透」

文章目录1.前言2.本地SFTP服务器搭建2.1.SFTP软件的下载和安装2.2.配置SFTP站点2.3.Cpolar下载和安装3.SFTP服务器的发布3.1.Cpolar云端设置3.2.Cpolar本地设置4.公网访问测试5.结语1.前言 现在的网络发达&#xff0c;个人电脑容量快速上升&#xff0c;想要保存的数据资料也越…...

ChatGPT优化Python代码的小技巧

使用 chatGPT 优化代码并降低运行时的云成本 许多开发人员说“过早的优化是万恶之源”。 这句话的来源归功于Donald Knuth。在他的书《计算机编程的艺术》中&#xff0c;他写道&#xff1a; “真正的问题是&#xff0c;程序员在错误的时间和错误的地方花费了太多时间来担心效率…...

Stm32-使用TB6612驱动电机及编码器测速

这里写目录标题起因一、电机及编码器的参数二、硬件三、接线四、驱动电机1、TB6612电机驱动2、定时器的PWM模式驱动电机五、编码器测速1、定时器的编码器接口模式2、定时器编码器模式测速的原理3、编码器模式的配置4、编码器模式相关代码5、测速方法六、相关问题以及解答1、编码…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

AIGC 基础篇 Python基础 02

1.bool类型 书接上回&#xff0c;我们上次最后讲了三大数据类型&#xff0c;除了这三个之外&#xff0c;Python也有bool类型&#xff0c;也就是True和False。 a 2 print(a1) print(a2) 像这里&#xff0c;输出的内容第一个是False&#xff0c;因为a的值为2&#xff0c;而第…...