ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【T-Rex Label底子教程】全新的主动化图片标注工具/软件 进步服从必备 可在 [打印本页]

作者: 种地    时间: 2024-10-26 06:05
标题: 【T-Rex Label底子教程】全新的主动化图片标注工具/软件 进步服从必备 可在
T-Rex Label是一种主动化辅助图片标注的工具,它可以使人们离开繁琐的传统标注流程(如LabelImg),极大地进步标注的服从。

话不多说,先来看一看主动化辅助标注的震撼结果:

那么该如何获取呢? T-Rex Label Github官网提供了在线和本地两种方式,这里为了克制繁琐的环境设置过程,选择T-Rex Label在线工具举行说明。(点击即可跳转)
以下从数据预备、图片导入、数据标注、标注导出、格式转换五个小节来说明T-Rex Label的使用流程。
0 数据预备

人们总是对例子情有独钟,为了资助你更好的理解操纵流程,我将通过一个案例来说明。
我们手中有如下的数据目录,Annotations_voc存放VOC格式的xml标注文件,Annotations_yolo存放YOLO格式的txt标注文件,当然现在还没有开始标注,他们都是空的,而pic中存放的是此次要标注的5张图片。

我们的目标是在T-Rex Label在线工具上对pic举行标注(把所有人头head标注出来),得到相应的Annotations_yolo标注文件(因为现在只支持导出COCO和YOLO格式),再使用yolo2voc.py(后续会提供)将YOLO格式转化为VOC格式,从而获取Annotations_voc 标注文件。

1 图片导入

打开在线工具链接后,在以下界面选择要导入的图片即可,现在最多支持一次导入200张图片并对其举行标注。

可以看到导入图片后如下,接着点击开始标注即可。

2 数据标注

下面用动图演示标注过程如下:
                                              ①                                       {\color{#E16B8C}{①}}                  ① 过程中因为预先没有界说分类,先按A键进入智能标注模式时,会提示你创建一个分类(e.g. head);

                                              ②                                       {\color{#E16B8C}{②}}                  ② 创建完成后,接着左键划标注框                                   →                              \rightarrow                  →Enter确定,如许一张图片的标注就完成了;

                                              ③                                       {\color{#E16B8C}{③}}                  ③ 过程中如果有划错的标注框,可以按Ctrl+Z回撤,也可以按D键进入选择模式,点击要删除的标定框后按Del键即可;
                                              ④                                       {\color{#E16B8C}{④}}                  ④ 过程中如果有AI漏标的对象,可以按R键进入手动标注模式举行框定;
                                              ⑤                                       {\color{#E16B8C}{⑤}}                  ⑤ 另外可以用小键盘上的左右方向键切换图片;
                                              ⑥                                       {\color{#E16B8C}{⑥}}                  ⑥ 建议先用智能标注完成一遍所有导入图片的粗标注,再用手动标注的方式举行精标注。
3 标注导出

所有图片都标注完成后导出标注即可。这里只可选择COCO或YOLO格式,我们先选择YOLO格式。

接着你会得到一个压缩包,解压后的文件目录如下,其中images是上传的原始图片,labels是YOLO格式的标注,classes是界说的分类。

到这儿,如果你需要的是YOLO或COCO格式,那么标注过程就完成了,如果你需要VOC格式,请看格式转换一节。
4 格式转换

首先创建一个如下图所示的项目目录:

                                              ①                                       {\color{#E16B8C}{①}}                  ① data图片导入一节中已经解说过了;
                                              ②                                       {\color{#E16B8C}{②}}                  ② 将下载解压得到的images中的图片放入pic中,将labels中的文件放入Annotations_yolo中,此时Annotations_voc仍为空;
                                              ③                                       {\color{#E16B8C}{③}}                  ③ 接着创建yolo2voc.py的转换函数(主要更改__main__的部分),运行即可在Annotations_voc中看到VOC格式的标注文件;
  1. # yolo2voc.py文件的内容
  2. from xml.dom.minidom import Document
  3. import os
  4. import cv2
  5. # 可以修改makexml定制化要写入xml的内容
  6. def makexml(picPath, txtPath, xmlPath,
  7.             folder_name="pic",  #图片文件建的名称
  8.             dirpath=".\\data\\pic\", #图片目录
  9.             ):
  10.     """此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件
  11.     """
  12.     dic = {'0': "head"}  # 创建字典用来对类型进行转换
  13.     files = os.listdir(txtPath)
  14.     for name in files:
  15.         xmlBuilder = Document()
  16.         annotation = xmlBuilder.createElement("annotation")
  17.         xmlBuilder.appendChild(annotation)
  18.         txtFile = open(os.path.join(txtPath, name))
  19.         txtList = txtFile.readlines()
  20.         img = cv2.imread(os.path.join(picPath, name[0:-4] + ".jpg"))
  21.         Pheight, Pwidth, Pdepth = img.shape
  22.         folder = xmlBuilder.createElement("folder")
  23.         foldercontent = xmlBuilder.createTextNode(folder_name)
  24.         folder.appendChild(foldercontent)
  25.         annotation.appendChild(folder)
  26.         filename = xmlBuilder.createElement("filename")
  27.         filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".jpg")
  28.         filename.appendChild(filenamecontent)
  29.         annotation.appendChild(filename)
  30.         path = xmlBuilder.createElement("path")
  31.         pathcontent = xmlBuilder.createTextNode(dirpath + name[0:-4] + ".jpg")
  32.         path.appendChild(pathcontent)
  33.         annotation.appendChild(path)
  34.         source = xmlBuilder.createElement("source")
  35.         annotation.appendChild(source)
  36.         database = xmlBuilder.createElement("database")
  37.         databasecontent = xmlBuilder.createTextNode("Unknown")
  38.         database.appendChild(databasecontent)
  39.         source.appendChild(database)
  40.         size = xmlBuilder.createElement("size")
  41.         width = xmlBuilder.createElement("width")
  42.         widthcontent = xmlBuilder.createTextNode(str(Pwidth))
  43.         width.appendChild(widthcontent)
  44.         size.appendChild(width)
  45.         height = xmlBuilder.createElement("height")
  46.         heightcontent = xmlBuilder.createTextNode(str(Pheight))
  47.         height.appendChild(heightcontent)
  48.         size.appendChild(height)
  49.         depth = xmlBuilder.createElement("depth")
  50.         depthcontent = xmlBuilder.createTextNode(str(Pdepth))
  51.         depth.appendChild(depthcontent)
  52.         size.appendChild(depth)
  53.         annotation.appendChild(size)
  54.         segmented = xmlBuilder.createElement("segmented")
  55.         segmentedcontent = xmlBuilder.createTextNode("0")
  56.         segmented.appendChild(segmentedcontent)
  57.         annotation.appendChild(segmented)
  58.         for j in txtList:
  59.             oneline = j.strip().split(" ")
  60.             object = xmlBuilder.createElement("object")
  61.             picname = xmlBuilder.createElement("name")
  62.             namecontent = xmlBuilder.createTextNode(dic[oneline[0]])
  63.             picname.appendChild(namecontent)
  64.             object.appendChild(picname)
  65.             pose = xmlBuilder.createElement("pose")
  66.             posecontent = xmlBuilder.createTextNode("Unspecified")
  67.             pose.appendChild(posecontent)
  68.             object.appendChild(pose)
  69.             truncated = xmlBuilder.createElement("truncated")
  70.             truncatedContent = xmlBuilder.createTextNode("0")
  71.             truncated.appendChild(truncatedContent)
  72.             object.appendChild(truncated)
  73.             difficult = xmlBuilder.createElement("difficult")
  74.             difficultcontent = xmlBuilder.createTextNode("0")
  75.             difficult.appendChild(difficultcontent)
  76.             object.appendChild(difficult)
  77.             bndbox = xmlBuilder.createElement("bndbox")
  78.             xmin = xmlBuilder.createElement("xmin")
  79.             mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)
  80.             xminContent = xmlBuilder.createTextNode(str(mathData))
  81.             xmin.appendChild(xminContent)
  82.             bndbox.appendChild(xmin)
  83.             ymin = xmlBuilder.createElement("ymin")
  84.             mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)
  85.             yminContent = xmlBuilder.createTextNode(str(mathData))
  86.             ymin.appendChild(yminContent)
  87.             bndbox.appendChild(ymin)
  88.             xmax = xmlBuilder.createElement("xmax")
  89.             mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)
  90.             xmaxContent = xmlBuilder.createTextNode(str(mathData))
  91.             xmax.appendChild(xmaxContent)
  92.             bndbox.appendChild(xmax)
  93.             ymax = xmlBuilder.createElement("ymax")
  94.             mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)
  95.             ymaxContent = xmlBuilder.createTextNode(str(mathData))
  96.             ymax.appendChild(ymaxContent)
  97.             bndbox.appendChild(ymax)
  98.             object.appendChild(bndbox)
  99.             annotation.appendChild(object)
  100.         # 使用字符串方式写入 XML 文件,避免生成 XML 声明
  101.         # 使用临时文件写入 XML
  102.         temp_xml_path = os.path.join(xmlPath, name[0:-4] + "_temp.xml")
  103.         with open(temp_xml_path, 'w', encoding='utf-8') as temp_file:
  104.             xmlBuilder.writexml(temp_file, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
  105.         # 读取临时 XML 文件并处理
  106.         with open(temp_xml_path, 'r', encoding='utf-8') as temp_file:
  107.             lines = temp_file.readlines()
  108.         # 删除第一行并缩进后面的行
  109.         with open(os.path.join(xmlPath, name[0:-4] + ".xml"), 'w', encoding='utf-8') as final_file:
  110.             for line in lines[1:]:  # 从第二行开始写入
  111.                 final_file.write(line[1:])  # 去掉每一行的第一个缩进
  112.         # 删除临时文件
  113.         os.remove(temp_xml_path)
  114. if __name__ == "__main__":
  115.     picPath = "data/pic/"  # 图片所在文件夹路径,后面的/一定要带上
  116.     txtPath = "data/Annotations_yolo/"  # txt所在文件夹路径,后面的/一定要带上
  117.     xmlPath = "data/Annotations_voc/"  # xml文件保存路径,后面的/一定要带上
  118.     makexml(picPath, txtPath, xmlPath,
  119.             folder_name="pic",
  120.             dirpath=".\\data\\pic\")
复制代码
                                             ④                                       {\color{#E16B8C}{④}}                  ④ 为了验证转换的精确性,使用demo.py文件(主要更改__main__的部分)可视化VOC标注的结果。
  1. # demo.py文件的内容
  2. import os
  3. import xml.etree.ElementTree as ET
  4. from PIL import Image, ImageDraw
  5. def parse_voc_xml(xml_file):
  6.     """解析 VOC 格式的 XML 文件,提取检测框信息"""
  7.     tree = ET.parse(xml_file)
  8.     root = tree.getroot()
  9.     boxes = []
  10.     for obj in root.findall('object'):
  11.         name = obj.find('name').text
  12.         xmlbox = obj.find('bndbox')
  13.         xmin = int(xmlbox.find('xmin').text)
  14.         ymin = int(xmlbox.find('ymin').text)
  15.         xmax = int(xmlbox.find('xmax').text)
  16.         ymax = int(xmlbox.find('ymax').text)
  17.         boxes.append((name, xmin, ymin, xmax, ymax))
  18.     return boxes
  19. def visualize_boxes(image_path, boxes):
  20.     """在图片上绘制检测框"""
  21.     image = Image.open(image_path)
  22.     draw = ImageDraw.Draw(image)
  23.     for box in boxes:
  24.         name, xmin, ymin, xmax, ymax = box
  25.         draw.rectangle([xmin, ymin, xmax, ymax], outline='red', width=3)
  26.         draw.text((xmin, ymin), name, fill='red')
  27.     return image
  28. def main(image_path, xml_path):
  29.     # 解析 XML 文件,获取检测框
  30.     boxes = parse_voc_xml(xml_path)
  31.     # 可视化检测框
  32.     visualized_image = visualize_boxes(image_path, boxes)
  33.     # 显示图片
  34.     visualized_image.show()
  35. if __name__ == "__main__":
  36.     # 输入图片和对应的 XML 文件路径
  37.     image_path = "data/pic/002861.jpg"  # 替换为你的图片路径
  38.     xml_path = "data/Annotations_voc/002861.xml"  # 替换为你的 XML 文件路径
  39.     main(image_path, xml_path)
复制代码
可以看到运行后的可视化结果如下,说明YOLO格式转VOC格式成功。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4