Yolov5数据检查、处理、格式转换


在这里插入图片描述

1.写这个帖子的初衷

最近在做基于yolov5目标检测的行人跌倒检测,在网上找了很久的图片数据(也有人家标注好的label,自己标注太慢了,好像下载的是百度飞桨)。不过拿到后放到模型中试了试,直接报错ZeroDivisionError…因为我是直接下载的人家的XML数据文件,转化之后就去调用了,没检查数据的有效性。根据报错发现有的图片文件属性不存在。
XML图片文件属性
就是圆圈的地方width或者height值为0,这样的XML文件在转换成txt文件时一定会报错。

2.想到的解决办法

对于这样的情况肯定是要把无效的XML文件拿出来然后重新用labelimg进行标注。下载的跌倒图片一共1442张,无效的图片不多,只需要将其重新标注再把原来的XML文件覆盖掉,最后所有图片转换txt。

3.期间遇到的小问题

——由于我是想写个程序,通过XML文件的size属性检测出无效的文件,然后按顺序打印出无效的图片名称,再将无效的图片文件复制到另一个文件夹方便标注。所以,就会出现一些不知道的东西…
—》涉及到文件操作,os.listdir(path)这句代码返回的是文件夹下所有文件的名称,但是是无序的。
—》检测到无效的XML文件,需要将其对应的jpg文件复制到别的文件夹下。
网上处理好的XML文件
这些数据文件命名一般都有规律。跌倒检测的标签比较简单,只涉及一个类别**‘fall’**。

4.处理阶段

----对于从网上找的一大堆图片文件,命名五花八门,而且还有的是webp类型文件,对于模型的数据文件,需要一定的处理(这里说的不是预处理)。
----对于非JPG,PNG的图片首先得格式转换—在线免费格式转换
----文件重命名代码很简单:
文件重命名
对于检索无效文件的思路,大致上是:

1.得到源XML文件夹下的所有的文件
2.依靠程序提取出文件名中的数字(因为模型数据大都是以数字+英文特征命名,比如**‘’fall_100.xml‘’**)
3.构建键值对,并对其排序(还涉及到元组、列表等)
4.利用copy函数复制无效文件

代码实现:

# coding=utf-8
import xml.dom.minidom
import re
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir , getcwd
from os.path import join
import glob
import shutil

'''
注意:尽量将需要检查的XML文件夹(如Annotations)、原始jpg文件夹(如images)、数据无效的XML文件所对应的新jpg文件夹(need_to_recharge)、
无效XML文件重新标注的labels文件夹尽量在同一目录下。

'''
path='E:/Yolov/yolov5_fall_detect/fall-detection-data-set-master/Annotations/' #需要修改mxl文件夹的地址
files=os.listdir(path) #得到文件夹下所有文件名称
key=[] #用来存放文件名中的数字,作为键
value=[]# 用来存放文件名,作为值

# 下面的程序主要是 按顺序 筛选出XML数据文件中  width  等无效文件
def read_width(file_name):
    in_file = open(path+file_name) #xml文件路径
    f = open(path+file_name)
    xml_text = f.read()
    root = ET.fromstring(xml_text)
    f.close()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)
    return w,h
for xmlFile in files: #遍历文件夹
    pattern=r'\d+' #正则表达式-提取字符串中的数字的规则
    match_obj=re.findall(pattern,xmlFile) #得到数字
    key.append(int(match_obj[0]))
    value.append(xmlFile)
file_right_order=dict(zip(key,value)) #构建键值对
file_name_tuplelist=list(zip(file_right_order.keys(),file_right_order.values()))#转为元组,方便排序
file_name_sortedlist=sorted(file_name_tuplelist,reverse=False)#升序排列,是一个以元组为元素的列表

file_name=[]   #按顺序排列的 XML文件名 列表
for index_tuple in file_name_sortedlist:
    file_name.append(index_tuple[1])

#下面将width或者height为0的 图片文件 复制到新的文件夹下,方便打loyov5标签
dstpath='E:/Yolov/yolov5_fall_detect/fall-detection-data-set-master/need_to_recharge'
picture_path='E:/Yolov/yolov5_fall_detect/fall-detection-data-set-master/images/' #跟XML文件夹同目录的图片文件夹
for XML_file in file_name:
    XML_filepath=os.path.join(path,XML_file)
    if not os.path.isdir(XML_filepath):
        w,h=read_width(XML_file)
        if w==0 or h==0:
            srcfile=picture_path+XML_file.split('.')[0]+'.jpg'  #无效的XML文件对应的image文件
            if not os.path.exists(dstpath):
                os.makedirs(dstpath)      
            shutil.copy(srcfile, dstpath)
            print(XML_file+'文件无效,对应的JPG文件已复制到'+dstpath+'文件夹下。')

检测成功并打印好的截图如下:

代码里面注释有点乱,这里我的文件层级如下(供参考,主要是方便看):
文件夹结构

5.附加一下格式转换代码

格式转换的代码我没看,直接拿来用了,算是搬个砖…YOLOV5的数据文件在打标签时,也是可以直接保存成txt。

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir , getcwd
from os.path import join
import glob

classes = ["fall"]
 
def convert(size, box):
 
    dw = 1.0/size[0]
    dh = 1.0/size[1]
    x = (box[0]+box[1])/2.0
    y = (box[2]+box[3])/2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x*dw
    w = w*dw
    y = y*dh
    h = h*dh
    return (x,y,w,h)
 
def convert_annotation(image_name):
    in_file = open('E:/Yolov/yolov5_fall_detect/fall-detection-data-set-master/Annotations/'+image_name[:-3]+'xml') #xml文件路径
    out_file = open('E:/Yolov/yolov5_fall_detect/fall-detection-data-set-master/XMLtoTxt/'+image_name[:-3]+'txt', 'w') #转换后的txt文件存放路径
    f = open('E:/Yolov/yolov5_fall_detect/fall-detection-data-set-master/Annotations/'+image_name[:-3]+'xml')
    xml_text = f.read()
    root = ET.fromstring(xml_text)
    f.close()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)
 
 
 
 
    for obj in root.iter('object'):
        cls = obj.find('name').text
        if cls not in classes:
            print(cls)
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
             float(xmlbox.find('ymax').text))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
 
wd = getcwd()
 
if __name__ == '__main__':
 
    for image_path in glob.glob("E:/Yolov/yolov5_fall_detect/fall-detection-data-set-master/images/*.jpg"): #每一张图片都对应一个xml文件这里写xml对应的图片的路径
        image_name = image_path.split('\\')[-1]
        convert_annotation(image_name)

6.结尾

在贴几张涉及到python基础知识的图片,以防后面又挖了,做个记录。
----->字典(键值对)
在这里插入图片描述
----->元组
在这里插入图片描述
----->re匹配数字
在这里插入图片描述
以上是我在学习的时候,遇到的问题,并加以总结!。。。就是怕自己忘的快,到时候遇到又得搜好一会儿。
Over!2024.03.14

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值