当前位置: 首页 > 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、编码…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

项目进度管理软件是什么?项目进度管理软件有哪些核心功能?

无论是建筑施工、软件开发&#xff0c;还是市场营销活动&#xff0c;项目往往涉及多个团队、大量资源和严格的时间表。如果没有一个系统化的工具来跟踪和管理这些元素&#xff0c;项目很容易陷入混乱&#xff0c;导致进度延误、成本超支&#xff0c;甚至失败。 项目进度管理软…...

LTR-381RGB-01RGB+环境光检测应用场景及客户类型主要有哪些?

RGB环境光检测 功能&#xff0c;在应用场景及客户类型&#xff1a; 1. 可应用的儿童玩具类型 (1) 智能互动玩具 功能&#xff1a;通过检测环境光或物体颜色触发互动&#xff08;如颜色识别积木、光感音乐盒&#xff09;。 客户参考&#xff1a; LEGO&#xff08;乐高&#x…...

生产管理系统开发:专业软件开发公司的实践与思考

生产管理系统开发的关键点 在当前制造业智能化升级的转型背景下&#xff0c;生产管理系统开发正逐步成为企业优化生产流程的重要技术手段。不同行业、不同规模的企业在推进生产管理数字化转型过程中&#xff0c;面临的挑战存在显著差异。本文结合具体实践案例&#xff0c;分析…...

【自然语言处理】大模型时代的数据标注(主动学习)

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构D 实验设计E 个人总结 A 论文出处 论文题目&#xff1a;FreeAL: Towards Human-Free Active Learning in the Era of Large Language Models发表情况&#xff1a;2023-EMNLP作者单位&#xff1a;浙江大…...