基于图像的半自动化标注、各个模型支持的数据集格式

执行代码:

绝对路径在Linux上

python detect.py --weights /root/user/yolov5/runs/train/exp40/weights/best.pt --source /root/user/yolov5/data/CowDetection02/test06

注:labelimg自动标注软件只支持YOLOv5s的训练模型和coco数据集中的80个类别。

首先自己标注小部分数据几十张也可以进行模型识别生成自己数据集的权重文件best.pt。然后,使用detect.py推理来完成大量照片的半自动化标注。恩非常完美很棒!如果有24级学弟学妹看到这里我想你应该已经帮我完成了剩下一半的半自动化标注了。

安装labelimg代码:

(base) C:\Users\ASUS>e:
python --version
(base) E:\>conda create -n labelimg python=3.8.19
(base) E:\> conda activate labelimg
(labelimg) E:\>pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple
(labelimg) E:\>labelimg

之前python版本是3.11结果安装完标注图像时会自动闪退,就降低虚拟环境下的python版本了。

step1:

在detect.py文件夹中修改下面两个参数: 

--save-txt  default=True 表述预测时保存label的 txt文件,会在runs/exp下生成一个labels

--nosave    default=False表述对预测的图片进行保存 True则是不保存

--classes 修改为19表示只识别牛,其他目标不识别就是不标框。

step2:

如果你想将生成的txt转化为xml

# 将 txt 标签 文件转换为 xml 标签文件, 修改dict中的类,以及xml  txt 和jpg 路径。

from xml.dom.minidom import Document
import os
import cv2

# 'person','head','helmet','lifejacket'
def makexml(txtPath,xmlPath,picPath): #读取txt路径,xml保存路径,数据集图片所在路径
        dict = {'0': "person",       #字典对类型进行转换,自己的标签的类。
                '1': "head",

               }
        files = os.listdir(txtPath)
        for i, name in enumerate(files):
          xmlBuilder = Document()
          annotation = xmlBuilder.createElement("annotation")  # 创建annotation标签
          xmlBuilder.appendChild(annotation)
          txtFile=open(txtPath+name)
          txtList = txtFile.readlines()
          img = cv2.imread(picPath+name[0:-4]+".jpg")
          Pheight,Pwidth,Pdepth=img.shape
          for i in txtList:
             oneline = i.strip().split(" ")

             folder = xmlBuilder.createElement("folder")#folder标签
             folderContent = xmlBuilder.createTextNode("VOC2007")
             folder.appendChild(folderContent)
             annotation.appendChild(folder)

             filename = xmlBuilder.createElement("filename")#filename标签
             filenameContent = xmlBuilder.createTextNode(name[0:-4]+".png")
             filename.appendChild(filenameContent)
             annotation.appendChild(filename)

             size = xmlBuilder.createElement("size")  # size标签
             width = xmlBuilder.createElement("width")  # size子标签width
             widthContent = xmlBuilder.createTextNode(str(Pwidth))
             width.appendChild(widthContent)
             size.appendChild(width)
             height = xmlBuilder.createElement("height")  # size子标签height
             heightContent = xmlBuilder.createTextNode(str(Pheight))
             height.appendChild(heightContent)
             size.appendChild(height)
             depth = xmlBuilder.createElement("depth")  # size子标签depth
             depthContent = xmlBuilder.createTextNode(str(Pdepth))
             depth.appendChild(depthContent)
             size.appendChild(depth)
             annotation.appendChild(size)

             object = xmlBuilder.createElement("object")
             picname = xmlBuilder.createElement("name")
             nameContent = xmlBuilder.createTextNode(dict[oneline[0]])
             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[1]))*Pwidth+1)-(float(oneline[3]))*0.5*Pwidth)
             xminContent = xmlBuilder.createTextNode(str(mathData))
             xmin.appendChild(xminContent)
             bndbox.appendChild(xmin)
             ymin = xmlBuilder.createElement("ymin")
             mathData = int(((float(oneline[2]))*Pheight+1)-(float(oneline[4]))*0.5*Pheight)
             yminContent = xmlBuilder.createTextNode(str(mathData))
             ymin.appendChild(yminContent)
             bndbox.appendChild(ymin)
             xmax = xmlBuilder.createElement("xmax")
             mathData = int(((float(oneline[1]))*Pwidth+1)+(float(oneline[3]))*0.5*Pwidth)
             xmaxContent = xmlBuilder.createTextNode(str(mathData))
             xmax.appendChild(xmaxContent)
             bndbox.appendChild(xmax)
             ymax = xmlBuilder.createElement("ymax")
             mathData = int(((float(oneline[2]))*Pheight+1)+(float(oneline[4]))*0.5*Pheight)
             ymaxContent = xmlBuilder.createTextNode(str(mathData))
             ymax.appendChild(ymaxContent)
             bndbox.appendChild(ymax)
             object.appendChild(bndbox)

             annotation.appendChild(object)

          f = open(xmlPath+name[0:-4]+".xml", 'w')
          xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
          f.close()

makexml("runs/detect/exp/labels/",               # txt文件夹
        "runs/detect/exp/xmls/",                 # xml文件夹
        "data/images/")                          # 图片数据文件夹

在YOLO中合并txt文件

import os



def concattxt(path1,path2):
        num = 0
        pathdir1 = os.listdir(path1)#获取第一部分txt文件夹中的文件列表

        for txtname in pathdir1:
                #name1 = os.path.splitext(txtname)[0]#获取当前txt文件名字
                #txtfile1 = open(txtpath1+name1, "rb")
                #txtfile2 = open(txtpath2+name1, "rb")
                txtfilepath1 = path1+txtname
                txtfilepath2 = path2+txtname
                txt1 = open(txtfilepath1,'a+', encoding='utf-8')
                if os.path.exists(txtfilepath2):
                        num = num+1
                        with open(txtfilepath2, 'r', encoding='utf-8') as txt2:
                                #txt1.write('\n')
                                for i in txt2:
                                         txt1.write(i)
        print('the concat txt num is:',num)


if __name__ == '__main__':
    txtpath1 = '/home/jun/work/2021Z001/test/ann/'
    txtpath2 = '/home/jun/work/2021Z001/test/labels/'
    concattxt(txtpath1,txtpath2)
 
 

划分数据集:

import os
import random
import re
import shutil

def create_folders():
    os.makedirs(r'F:\yoloslowfast\train01\images\train', exist_ok=True)
    os.makedirs(r'F:\yoloslowfast\train01\images\val', exist_ok=True)
    os.makedirs(r'F:\yoloslowfast\train01\labels\train', exist_ok=True)
    os.makedirs(r'F:\yoloslowfast\train01\labels\val', exist_ok=True)

def split_data(path_images, path_labels, rate):
    images_list = os.listdir(path_images)
    for img_file in images_list:
        img_id = re.match(r'(.*)\.(jpg|png)', img_file)
        if img_id:
            img_id = img_id.group(1)
            label_file = img_id + '.txt'
            prob = random.randint(1, 100)
            if prob < rate:
                src_img = os.path.join(path_images, img_file)
                dst_img = os.path.join(r'F:\yoloslowfast\train01\images\train', img_file)
                src_label = os.path.join(path_labels, label_file)
                dst_label = os.path.join(r'F:\yoloslowfast\train01\labels\train', label_file)
            else:
                src_img = os.path.join(path_images, img_file)
                dst_img = os.path.join(r'F:\yoloslowfast\train01\images\val', img_file)
                src_label = os.path.join(path_labels, label_file)
                dst_label = os.path.join(r'F:\yoloslowfast\train01\labels\val', label_file)
            
            shutil.copy(src_img, dst_img)
            shutil.copy(src_label, dst_label)

if __name__ == '__main__':
    path_images = r'F:\yoloslowfast\train01\images'
    path_labels = r'F:\yoloslowfast\train01\labels'
    rate = 70  # 可以调整训练集和验证集的比例

    create_folders()
    split_data(path_images, path_labels, rate)

YOLOv5中牛类别是19:

step3:

将最开始测试图片和得到的labels文件夹放在一起,使用labelImg打开该文件夹。

打开labelImg之前,先在labels文件夹下手动创建一个classes.txt文件,里面写上你的类别名称,防止labelImg的闪退。

 数据集划分:

import os
import random
import re
import shutil
def creat_files():
    try:
        shutil.rmtree('./data//images')
        shutil.rmtree('./data/labels')
    except:
        pass
    try:
        os.makedirs('./data/images/train')
        os.makedirs('./data/images/val')
        os.makedirs('./data/labels/train')
        os.makedirs('./data/labels/val')
    except:
        pass
def read_files(path):
    dir_list = os.listdir(path)
    for i in dir_list:
        #利用正则表达,切割出图片ID
        image_id = re.match(r'(.*)?.(jpg|png)',i).group(1)#图片后缀为jpg,png,可自行添加后缀格式
        labels_name = image_id+'.txt' #由图片ID找到对应标签名
        prob = random.randint(1, 100)#随机数prob
        if (prob < rate):  # train dataset
            old_images_path = path_images + '/' + i
            new_images_path = './data/images/train' + '/' + i
            old_labels_path = path_labels + '/'+ labels_name
            new_labels_path = './data/labels/train' + '/' + labels_name
            shutil.copy(old_images_path, new_images_path)
            shutil.copy(old_labels_path, new_labels_path)
        else:  # val dataset
            old_images_path = path_images + '/' + i
            new_images_path = './data/images/val' + '/' + i
            old_labels_path = path_labels + '/' + labels_name
            new_labels_path = './data/labels/val' + '/' + labels_name
            shutil.copy(old_images_path, new_images_path)
            shutil.copy(old_labels_path, new_labels_path)
 
if __name__ == '__main__':
    path_images = './images' #图片的路径
    path_labels = './labels' #标签路径
    rate = 90  # (1-100)之间,90即练集与验证集比例9:1,可以改成自己喜欢的比例
    creat_files()
    read_files(path_images)

训练集:在训练阶段我们要用训练集来训练模型,用验证集来验证你训练的模型效果

验证集:在训练阶段去使用,辅助模型训练。

测试集:模型训练好之后,最终对模型做出评估。

OK,以上就是官方使用YOLOv5与labelimg实现半自动标注。

ImageNet支持xml格式

YOLO支持txt格式

待总结数据集格式及各个网络模型所支持的

yolo半自动标注实现流程

1、72张照片手动标注,两个动作站立和走动。

2、在yolo中训练模型并获得最好权重

修改配置文件:yolov5s.yaml中nc修改成自己数据集的类别

修改coco.yaml,把类别和数据集文件路径换成自己的

文件路径 

必须得是images和labels命名,不然会报错的。

以上即是加入自己的数据集需要修改的地方。

训练结果:训练完后拿到了一个最好权重和最后一次权重。

训练:

验证:

 

问题很多或者改进地方很多,下用YOLO半自动标注这个事搞完再慢慢说吧! 

 修改detect.py中的save-txt在最上面和执行detect

python detect.py --weights /root/user/yolov5/runs/train/exp40/weights/best.pt --source /root/user/yolov5/data/CowDetection02/test06

确实生成了txt文件

遇到问题:

1、无法对自动标注的框进行操作

2、行为也是错的,应该是两个walk一个stand,可能和训练集样本有关系。 

问题终于解决了,总结一下。

第一个问题:detect.py检测的照片在labelimg中打开会出现置信度和修改不了照片位置问题

第二个问题:detect.py检测的照片在labelimg中打开出现修改照片位置或类别名出线闪退问题

问题已解决

数据集标注注意事项:

1、从视频里抽帧、去重、缩放后对图片重命名。再筛选图片,筛选完对图片进行标注及半自动标注,划分数据集。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值