种地 发表于 2024-10-26 06:05:11

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

T-Rex Label是一种主动化辅助图片标注的工具,它可以使人们离开繁琐的传统标注流程(如LabelImg),极大地进步标注的服从。
https://i-blog.csdnimg.cn/direct/4240bdd63a1a4dbd8e378eade3ab41aa.png
话不多说,先来看一看主动化辅助标注的震撼结果:
https://i-blog.csdnimg.cn/direct/5d69f34e44ee43b4b7396b703eef0b5f.gif#pic_center
那么该如何获取呢? T-Rex Label Github官网提供了在线和本地两种方式,这里为了克制繁琐的环境设置过程,选择T-Rex Label在线工具举行说明。(点击即可跳转)
以下从数据预备、图片导入、数据标注、标注导出、格式转换五个小节来说明T-Rex Label的使用流程。
0 数据预备

人们总是对例子情有独钟,为了资助你更好的理解操纵流程,我将通过一个案例来说明。
我们手中有如下的数据目录,Annotations_voc存放VOC格式的xml标注文件,Annotations_yolo存放YOLO格式的txt标注文件,当然现在还没有开始标注,他们都是空的,而pic中存放的是此次要标注的5张图片。
https://i-blog.csdnimg.cn/direct/45fa453055ef430183bbd8d725ff1db4.png
我们的目标是在T-Rex Label在线工具上对pic举行标注(把所有人头head标注出来),得到相应的Annotations_yolo标注文件(因为现在只支持导出COCO和YOLO格式),再使用yolo2voc.py(后续会提供)将YOLO格式转化为VOC格式,从而获取Annotations_voc 标注文件。
https://i-blog.csdnimg.cn/direct/a44179b75ec64dbfb4b64efd56d89cdb.jpeg
1 图片导入

打开在线工具链接后,在以下界面选择要导入的图片即可,现在最多支持一次导入200张图片并对其举行标注。
https://i-blog.csdnimg.cn/direct/58883a7acd8745808a09c69b88d0ce5b.png
可以看到导入图片后如下,接着点击开始标注即可。
https://i-blog.csdnimg.cn/direct/d0f14a09c6f54c34844e663fb0b56238.png
2 数据标注

下面用动图演示标注过程如下:
                                              ①                                       {\color{#E16B8C}{①}}                  ① 过程中因为预先没有界说分类,先按A键进入智能标注模式时,会提示你创建一个分类(e.g. head);
https://i-blog.csdnimg.cn/direct/a146bcefc5414e3393ec041df98b6484.gif
                                              ②                                       {\color{#E16B8C}{②}}                  ② 创建完成后,接着左键划标注框                                 →                              \rightarrow                  →Enter确定,如许一张图片的标注就完成了;
https://i-blog.csdnimg.cn/direct/ff3cf48beb4745c69aaba0b40489bb3f.gif
                                              ③                                       {\color{#E16B8C}{③}}                  ③ 过程中如果有划错的标注框,可以按Ctrl+Z回撤,也可以按D键进入选择模式,点击要删除的标定框后按Del键即可;
                                              ④                                       {\color{#E16B8C}{④}}                  ④ 过程中如果有AI漏标的对象,可以按R键进入手动标注模式举行框定;
                                              ⑤                                       {\color{#E16B8C}{⑤}}                  ⑤ 另外可以用小键盘上的左右方向键切换图片;
                                              ⑥                                       {\color{#E16B8C}{⑥}}                  ⑥ 建议先用智能标注完成一遍所有导入图片的粗标注,再用手动标注的方式举行精标注。
3 标注导出

所有图片都标注完成后导出标注即可。这里只可选择COCO或YOLO格式,我们先选择YOLO格式。
https://i-blog.csdnimg.cn/direct/bb32abe625584a28adc02d310a3791c5.png
接着你会得到一个压缩包,解压后的文件目录如下,其中images是上传的原始图片,labels是YOLO格式的标注,classes是界说的分类。
https://i-blog.csdnimg.cn/direct/ef1203615b324276911d168dfb5ad9f2.png
到这儿,如果你需要的是YOLO或COCO格式,那么标注过程就完成了,如果你需要VOC格式,请看格式转换一节。
4 格式转换

首先创建一个如下图所示的项目目录:
https://i-blog.csdnimg.cn/direct/fc6ccfa2c3404b579a1f89aba2076e5c.png
                                              ①                                       {\color{#E16B8C}{①}}                  ① data在图片导入一节中已经解说过了;
                                              ②                                       {\color{#E16B8C}{②}}                  ② 将下载解压得到的images中的图片放入pic中,将labels中的文件放入Annotations_yolo中,此时Annotations_voc仍为空;
                                              ③                                       {\color{#E16B8C}{③}}                  ③ 接着创建yolo2voc.py的转换函数(主要更改__main__的部分),运行即可在Annotations_voc中看到VOC格式的标注文件;
# yolo2voc.py文件的内容
from xml.dom.minidom import Document
import os
import cv2
# 可以修改makexml定制化要写入xml的内容
def makexml(picPath, txtPath, xmlPath,
            folder_name="pic",#图片文件建的名称
            dirpath=".\\data\\pic\\", #图片目录
            ):
    """此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件
    """
    dic = {'0': "head"}# 创建字典用来对类型进行转换
    files = os.listdir(txtPath)

    for name in files:
      xmlBuilder = Document()
      annotation = xmlBuilder.createElement("annotation")
      xmlBuilder.appendChild(annotation)

      txtFile = open(os.path.join(txtPath, name))
      txtList = txtFile.readlines()
      img = cv2.imread(os.path.join(picPath, name + ".jpg"))
      Pheight, Pwidth, Pdepth = img.shape

      folder = xmlBuilder.createElement("folder")
      foldercontent = xmlBuilder.createTextNode(folder_name)
      folder.appendChild(foldercontent)
      annotation.appendChild(folder)

      filename = xmlBuilder.createElement("filename")
      filenamecontent = xmlBuilder.createTextNode(name + ".jpg")
      filename.appendChild(filenamecontent)
      annotation.appendChild(filename)

      path = xmlBuilder.createElement("path")
      pathcontent = xmlBuilder.createTextNode(dirpath + name + ".jpg")
      path.appendChild(pathcontent)
      annotation.appendChild(path)

      source = xmlBuilder.createElement("source")
      annotation.appendChild(source)
      database = xmlBuilder.createElement("database")
      databasecontent = xmlBuilder.createTextNode("Unknown")
      database.appendChild(databasecontent)
      source.appendChild(database)

      size = xmlBuilder.createElement("size")
      width = xmlBuilder.createElement("width")
      widthcontent = xmlBuilder.createTextNode(str(Pwidth))
      width.appendChild(widthcontent)
      size.appendChild(width)

      height = xmlBuilder.createElement("height")
      heightcontent = xmlBuilder.createTextNode(str(Pheight))
      height.appendChild(heightcontent)
      size.appendChild(height)

      depth = xmlBuilder.createElement("depth")
      depthcontent = xmlBuilder.createTextNode(str(Pdepth))
      depth.appendChild(depthcontent)
      size.appendChild(depth)

      annotation.appendChild(size)

      segmented = xmlBuilder.createElement("segmented")
      segmentedcontent = xmlBuilder.createTextNode("0")
      segmented.appendChild(segmentedcontent)
      annotation.appendChild(segmented)

      for j in txtList:
            oneline = j.strip().split(" ")
            object = xmlBuilder.createElement("object")
            picname = xmlBuilder.createElement("name")
            namecontent = xmlBuilder.createTextNode(dic])
            picname.appendChild(namecontent)
            object.appendChild(picname)

            pose = xmlBuilder.createElement("pose")
            posecontent = xmlBuilder.createTextNode("Unspecified")
            pose.appendChild(posecontent)
            object.appendChild(pose)

            truncated = xmlBuilder.createElement("truncated")
            truncatedContent = xmlBuilder.createTextNode("0")
            truncated.appendChild(truncatedContent)
            object.appendChild(truncated)

            difficult = xmlBuilder.createElement("difficult")
            difficultcontent = xmlBuilder.createTextNode("0")
            difficult.appendChild(difficultcontent)
            object.appendChild(difficult)

            bndbox = xmlBuilder.createElement("bndbox")

            xmin = xmlBuilder.createElement("xmin")
            mathData = int(((float(oneline)) * Pwidth + 1) - (float(oneline)) * 0.5 * Pwidth)
            xminContent = xmlBuilder.createTextNode(str(mathData))
            xmin.appendChild(xminContent)
            bndbox.appendChild(xmin)

            ymin = xmlBuilder.createElement("ymin")
            mathData = int(((float(oneline)) * Pheight + 1) - (float(oneline)) * 0.5 * Pheight)
            yminContent = xmlBuilder.createTextNode(str(mathData))
            ymin.appendChild(yminContent)
            bndbox.appendChild(ymin)

            xmax = xmlBuilder.createElement("xmax")
            mathData = int(((float(oneline)) * Pwidth + 1) + (float(oneline)) * 0.5 * Pwidth)
            xmaxContent = xmlBuilder.createTextNode(str(mathData))
            xmax.appendChild(xmaxContent)
            bndbox.appendChild(xmax)

            ymax = xmlBuilder.createElement("ymax")
            mathData = int(((float(oneline)) * Pheight + 1) + (float(oneline)) * 0.5 * Pheight)
            ymaxContent = xmlBuilder.createTextNode(str(mathData))
            ymax.appendChild(ymaxContent)
            bndbox.appendChild(ymax)

            object.appendChild(bndbox)
            annotation.appendChild(object)

      # 使用字符串方式写入 XML 文件,避免生成 XML 声明
      # 使用临时文件写入 XML
      temp_xml_path = os.path.join(xmlPath, name + "_temp.xml")
      with open(temp_xml_path, 'w', encoding='utf-8') as temp_file:
            xmlBuilder.writexml(temp_file, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
      # 读取临时 XML 文件并处理
      with open(temp_xml_path, 'r', encoding='utf-8') as temp_file:
            lines = temp_file.readlines()
      # 删除第一行并缩进后面的行
      with open(os.path.join(xmlPath, name + ".xml"), 'w', encoding='utf-8') as final_file:
            for line in lines:# 从第二行开始写入
                final_file.write(line)# 去掉每一行的第一个缩进
      # 删除临时文件
      os.remove(temp_xml_path)

if __name__ == "__main__":
    picPath = "data/pic/"# 图片所在文件夹路径,后面的/一定要带上
    txtPath = "data/Annotations_yolo/"# txt所在文件夹路径,后面的/一定要带上
    xmlPath = "data/Annotations_voc/"# xml文件保存路径,后面的/一定要带上
    makexml(picPath, txtPath, xmlPath,
            folder_name="pic",
            dirpath=".\\data\\pic\\")
                                              ④                                       {\color{#E16B8C}{④}}                  ④ 为了验证转换的精确性,使用demo.py文件(主要更改__main__的部分)可视化VOC标注的结果。
# demo.py文件的内容
import os
import xml.etree.ElementTree as ET
from PIL import Image, ImageDraw

def parse_voc_xml(xml_file):
    """解析 VOC 格式的 XML 文件,提取检测框信息"""
    tree = ET.parse(xml_file)
    root = tree.getroot()
    boxes = []
    for obj in root.findall('object'):
      name = obj.find('name').text
      xmlbox = obj.find('bndbox')
      xmin = int(xmlbox.find('xmin').text)
      ymin = int(xmlbox.find('ymin').text)
      xmax = int(xmlbox.find('xmax').text)
      ymax = int(xmlbox.find('ymax').text)
      boxes.append((name, xmin, ymin, xmax, ymax))
    return boxes

def visualize_boxes(image_path, boxes):
    """在图片上绘制检测框"""
    image = Image.open(image_path)
    draw = ImageDraw.Draw(image)
    for box in boxes:
      name, xmin, ymin, xmax, ymax = box
      draw.rectangle(, outline='red', width=3)
      draw.text((xmin, ymin), name, fill='red')
    return image

def main(image_path, xml_path):
    # 解析 XML 文件,获取检测框
    boxes = parse_voc_xml(xml_path)
    # 可视化检测框
    visualized_image = visualize_boxes(image_path, boxes)
    # 显示图片
    visualized_image.show()

if __name__ == "__main__":
    # 输入图片和对应的 XML 文件路径
    image_path = "data/pic/002861.jpg"# 替换为你的图片路径
    xml_path = "data/Annotations_voc/002861.xml"# 替换为你的 XML 文件路径
    main(image_path, xml_path)
可以看到运行后的可视化结果如下,说明YOLO格式转VOC格式成功。
https://i-blog.csdnimg.cn/direct/969fcd15e6aa48d082600b5d2d48c348.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【T-Rex Label底子教程】全新的主动化图片标注工具/软件 进步服从必备 可在