文章目录

  • Widerface数据集转VOC格式
  • VOC 转YOLO格式
  • 数据集的imageslisttxt
  • YOLOv5训练
  • 检查yolo labels对不对
  • 并行训练

Widerface数据集转VOC格式

标注是:

下面程序folderFile 字典定义了数据集存储的位置信息,VOCrootpath 给出了VOC存储地址。

# coding:utf-8
import os.path
from xml.dom.minidom import Document
import cv2
import numpy as npdef writexml(filename, saveimg, bboxes, xmlpath):doc = Document()annotation = doc.createElement('annotation')doc.appendChild(annotation)folder = doc.createElement('folder')folder_name = doc.createTextNode('widerface')folder.appendChild(folder_name)annotation.appendChild(folder)filenamenode = doc.createElement('filename')filename_name = doc.createTextNode(filename)filenamenode.appendChild(filename_name)annotation.appendChild(filenamenode)source = doc.createElement('source')annotation.appendChild(source)database = doc.createElement('database')database.appendChild(doc.createTextNode('wider face Database'))source.appendChild(database)annotation_s = doc.createElement('annotation')annotation_s.appendChild(doc.createTextNode('PASCAL VOC2007'))source.appendChild(annotation_s)image = doc.createElement('image')image.appendChild(doc.createTextNode('flickr'))source.appendChild(image)flickrid = doc.createElement('flickrid')flickrid.appendChild(doc.createTextNode('-1'))source.appendChild(flickrid)owner = doc.createElement('owner')annotation.appendChild(owner)flickrid_o = doc.createElement('flickrid')flickrid_o.appendChild(doc.createTextNode('muke'))owner.appendChild(flickrid_o)name_o = doc.createElement('name')name_o.appendChild(doc.createTextNode('muke'))owner.appendChild(name_o)size = doc.createElement('size')annotation.appendChild(size)width = doc.createElement('width')width.appendChild(doc.createTextNode(str(saveimg.shape[1])))height = doc.createElement('height')height.appendChild(doc.createTextNode(str(saveimg.shape[0])))depth = doc.createElement('depth')depth.appendChild(doc.createTextNode(str(saveimg.shape[2])))size.appendChild(width)size.appendChild(height)size.appendChild(depth)segmented = doc.createElement('segmented')segmented.appendChild(doc.createTextNode('0'))annotation.appendChild(segmented)for i in range(len(bboxes)):bbox = bboxes[i]objects = doc.createElement('object')annotation.appendChild(objects)object_name = doc.createElement('name')object_name.appendChild(doc.createTextNode('face'))objects.appendChild(object_name)pose = doc.createElement('pose')pose.appendChild(doc.createTextNode('Unspecified'))objects.appendChild(pose)truncated = doc.createElement('truncated')truncated.appendChild(doc.createTextNode('0'))objects.appendChild(truncated)difficult = doc.createElement('difficult')difficult.appendChild(doc.createTextNode('0'))objects.appendChild(difficult)bndbox = doc.createElement('bndbox')objects.appendChild(bndbox)xmin = doc.createElement('xmin')xmin.appendChild(doc.createTextNode(str(bbox[0])))bndbox.appendChild(xmin)ymin = doc.createElement('ymin')ymin.appendChild(doc.createTextNode(str(bbox[1])))bndbox.appendChild(ymin)xmax = doc.createElement('xmax')xmax.appendChild(doc.createTextNode(str(bbox[0] + bbox[2])))bndbox.appendChild(xmax)ymax = doc.createElement('ymax')ymax.appendChild(doc.createTextNode(str(bbox[1] + bbox[3])))bndbox.appendChild(ymax)f = open(xmlpath, "w")f.write(doc.toprettyxml(indent=''))f.close()if __name__ == '__main__':# 给出下面五个路径folderFile = {"traintxt": r"E:\WIIDERFACE\wider_face_split\wider_face_split\wider_face_train_bbx_gt.txt","trainimagepath": r"E:\WIIDERFACE\WIDER_train\WIDER_train\images","valtxt": r"E:\WIIDERFACE\wider_face_split\wider_face_split\wider_face_val_bbx_gt.txt","valimagepath": r"E:\WIIDERFACE\WIDER_val\WIDER_val\images","texttxt": r"E:\WIIDERFACE\wider_face_split\wider_face_split\wider_face_test_filelist.txt","textimagepath": r"E:\WIIDERFACE\WIDER_test\WIDER_test\images", }# 给出VOC数据存储地址VOCrootpath = r"E:\WIIDERFACE\WIDER_VOC"needPath = [os.path.join(VOCrootpath, "train", "Annotations"),os.path.join(VOCrootpath, "train", "JPEGImages"),os.path.join(VOCrootpath, "val", "Annotations"),os.path.join(VOCrootpath, "val", "JPEGImages"),os.path.join(VOCrootpath, "test", "JPEGImages"), ]for ph in needPath:if not os.path.exists(ph):os.makedirs(ph)for gtfile, gtimages, imgsavepath, vocxmlsavepath in [(folderFile["traintxt"], folderFile["trainimagepath"], needPath[1], needPath[0]),(folderFile["valtxt"], folderFile["valimagepath"], needPath[3], needPath[2])]:with open(gtfile, "r", encoding="utf-8") as f:while True:gt_con = f.readline().strip()if gt_con is None or gt_con == "":breakim_path = os.path.join(gtimages, gt_con)im_data = cv2.imdecode(np.fromfile(im_path, dtype=np.uint8), 1)  # img是矩阵if im_data is None:continuenumbox = int(f.readline())bboxes = []if numbox == 0:  # numbox 为0 的情况处理f.readline()else:for i in range(numbox):line = f.readline()infos = line.split(" ")  # 用空格分割bbox = (int(infos[0]), int(infos[1]), int(infos[2]), int(infos[3]))bboxes.append(bbox)  # 将一张图片的所有人脸数据加入bboxesfilename = gt_con.replace("/", "_").replace("-", "_")[:-4]  # 将存储位置作为图片名称,斜杠转为下划线cv2.imencode('.jpg', im_data)[1].tofile(os.path.join(imgsavepath, filename + ".jpg"))xmlpath = os.path.join(vocxmlsavepath, filename + ".xml")writexml(filename, im_data, bboxes, xmlpath)gtfile = folderFile["texttxt"]gtimages = folderFile["textimagepath"]imgsavepath = needPath[4]with open(gtfile, "r", encoding="utf-8") as f:while True:gt_con = f.readline().strip()if gt_con is None or gt_con == "":breakim_path = os.path.join(gtimages, gt_con)im_data = cv2.imdecode(np.fromfile(im_path, dtype=np.uint8), 1)  # img是矩阵if im_data is None:continuefilename = gt_con.replace("/", "_").replace("-", "_")[:-4]  # 将存储位置作为图片名称,斜杠转为下划线cv2.imencode('.jpg', im_data)[1].tofile(os.path.join(imgsavepath, filename + ".jpg"))

VOC 转YOLO格式

YOLO格式:

下面的代码会在各自的Annotations同级目录创建出labels文件夹,然后将Annotations内的xml标注转换成yolov5的标注文件:

# coding:utf-8
import os
import os.path
import xml.etree.ElementTree as ETdef convert_annotation(xmldir: str, txtdir: str, image_id: str, classes: dict):in_file = open(os.path.join(xmldir, '%s.xml' % (image_id)), 'r', encoding='UTF-8')out_file = open(os.path.join(txtdir, '%s.txt' % (image_id)), 'w')tree = ET.parse(in_file)root = tree.getroot()size = root.find('size')size_width = int(size.find('width').text)size_height = int(size.find('height').text)for obj in root.iter('object'):difficult = obj.find('difficult').textcls = obj.find('name').textif cls not in classes or int(difficult) == 1:continuecls_id = classes[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)]if size_width == 0 or size_height == 0 or b[0] == b[1] or b[2] == b[3]:print("不合理的图不再给labels  ", image_id)# if os.path.exists(xmldir + '%s.xml' % (image_id)):#     os.remove(xmldir + '%s.xml' % (image_id))out_file.close()os.remove(os.path.join(txtdir, '%s.txt' % (image_id)))return 1# 标注越界修正if b[0] < 0:b[0] = 0if b[1] > size_width:b[1] = size_widthif b[2] < 0:b[2] = 0if b[3] > size_height:b[3] = size_heighttxt_data = [round(((b[0] + b[1]) / 2.0 - 1) / size_width, 6),round(((b[2] + b[3]) / 2.0 - 1) / size_height, 6),round((b[1] - b[0]) / size_width, 6),round((b[3] - b[2]) / size_height, 6)]if txt_data[0] < 0 or txt_data[1] < 0 or txt_data[2] < 0 or txt_data[3] < 0:print("不合理的图不再给labels  ", image_id)out_file.close()os.remove(os.path.join(txtdir, '%s.txt' % (image_id)))return 1out_file.write(str(cls_id) + " " + " ".join([str(a) for a in txt_data]) + '\n')in_file.close()out_file.close()return 0def listPathAllfiles(dirname):result = []for maindir, subdir, file_name_list in os.walk(dirname):for filename in file_name_list:apath = os.path.join(maindir, filename)result.append(apath)return resultif __name__ == '__main__':classes = {'face': 0}  # 标签名:标签id# 给出VOC数据存储地址VOCrootpath = r"E:\WIIDERFACE\WIDER_VOC"needPath = [os.path.join(VOCrootpath, "train", "Annotations"),os.path.join(VOCrootpath, "train", "JPEGImages"),os.path.join(VOCrootpath, "val", "Annotations"),os.path.join(VOCrootpath, "val", "JPEGImages"),os.path.join(VOCrootpath, "test", "JPEGImages"),os.path.join(VOCrootpath, "train", "labels"),os.path.join(VOCrootpath, "val", "labels"), ]for ph in needPath:if not os.path.exists(ph):os.makedirs(ph)for xmlpath, txtpath in [[needPath[0], needPath[5]],[needPath[2], needPath[6]]]:allfiles = listPathAllfiles(xmlpath)print("一共有文件个数:", len(allfiles))failNum = 0for xmlName in allfiles:# xml存储路径,yololabels存储路径,xml文件名称不带.xml后缀,需要的类及其类id的字典if convert_annotation(xmlpath, txtpath, os.path.basename(xmlName)[:-4], classes) == 1:failNum += 1print("失败了多少个文件的labels:", failNum)

会遇到一些xml里面标注不合规,但是没多少,无关紧要了。但得注意,标签不行就不要给txt文件,里面没内容的txt文件yolo会认为是对应图里没目标。

C:\Users\dong.xie\.conda\envs\py38\python.exe C:/Users/dong.xie/Desktop/workcode/kevintest/dataset_cleaner/005VOC转yolo.py
一共有文件个数: 12880
不合理的图不再给labels   0__Parade_0_Parade_Parade_0_452
不合理的图不再给labels   12__Group_12_Group_Large_Group_12_Group_Large_Group_12_31
不合理的图不再给labels   29__Students_Schoolkids_29_Students_Schoolkids_Students_Schoolkids_29_230
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstration_Or_Protest_2_202
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstration_Or_Protest_2_520
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstration_Or_Protest_2_543
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstration_Or_Protest_2_546
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstration_Or_Protest_2_666
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstrators_2_206
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstrators_2_373
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstrators_2_559
不合理的图不再给labels   2__Demonstration_2_Demonstration_Political_Rally_2_444
不合理的图不再给labels   2__Demonstration_2_Demonstration_Political_Rally_2_71
不合理的图不再给labels   2__Demonstration_2_Demonstration_Protesters_2_346
不合理的图不再给labels   33__Running_33_Running_Running_33_660
不合理的图不再给labels   35__Basketball_35_Basketball_basketballgame_ball_35_805
不合理的图不再给labels   35__Basketball_35_Basketball_Basketball_35_102
不合理的图不再给labels   35__Basketball_35_Basketball_Basketball_35_220
不合理的图不再给labels   36__Football_36_Football_americanfootball_ball_36_184
不合理的图不再给labels   36__Football_36_Football_Football_36_63
不合理的图不再给labels   39__Ice_Skating_39_Ice_Skating_iceskiing_39_380
不合理的图不再给labels   46__Jockey_46_Jockey_Jockey_46_576
不合理的图不再给labels   46__Jockey_46_Jockey_Jockey_46_717
不合理的图不再给labels   48__Parachutist_Paratrooper_48_Parachutist_Paratrooper_Parachutist_Paratrooper_48_258
不合理的图不再给labels   48__Parachutist_Paratrooper_48_Parachutist_Paratrooper_Parachutist_Paratrooper_48_283
不合理的图不再给labels   54__Rescue_54_Rescue_rescuepeople_54_29
不合理的图不再给labels   58__Hockey_58_Hockey_icehockey_puck_58_947
不合理的图不再给labels   7__Cheering_7_Cheering_Cheering_7_17
失败了多少个文件的labels: 28
一共有文件个数: 3226
不合理的图不再给labels   0__Parade_0_Parade_Parade_0_275
不合理的图不再给labels   0__Parade_0_Parade_Parade_0_317
不合理的图不再给labels   2__Demonstration_2_Demonstration_Demonstration_Or_Protest_2_476
不合理的图不再给labels   2__Demonstration_2_Demonstration_Political_Rally_2_335
不合理的图不再给labels   37__Soccer_37_Soccer_soccer_ball_37_281
不合理的图不再给labels   39__Ice_Skating_39_Ice_Skating_iceskiing_39_583
不合理的图不再给labels   50__Celebration_Or_Party_50_Celebration_Or_Party_houseparty_50_715
不合理的图不再给labels   7__Cheering_7_Cheering_Cheering_7_171
不合理的图不再给labels   7__Cheering_7_Cheering_Cheering_7_426
失败了多少个文件的labels: 9Process finished with exit code 0

数据集的imageslisttxt

此时获得了这样的文件层级结构:
E:\WIIDERFACE\WIDER_VOC
├─test
│ └─JPEGImages
├─train
│ ├─Annotations
│ ├─JPEGImages
│ └─labels
└─val
├─Annotations
├─JPEGImages
└─labels

为了便于yolov5识别,将三个JPEGImages名称改写为images。
同时,生成三个images的txtlist便于yolov5识别,下面程序即会在E:\WIIDERFACE\WIDER_VOC目录生成对应imageslisttxt:

import osdef listPathAllfiles(dirname):result = []for maindir, subdir, file_name_list in os.walk(dirname):for filename in file_name_list:apath = os.path.join(maindir, filename)result.append(apath)return resultif __name__ == '__main__':classes = {'face': 0}  # 标签名:标签id# 给出VOC数据存储地址VOCrootpath = r"E:\WIIDERFACE\WIDER_VOC"needPath = [os.path.join(VOCrootpath, "train", "Annotations"),os.path.join(VOCrootpath, "train", "images"),os.path.join(VOCrootpath, "val", "Annotations"),os.path.join(VOCrootpath, "val", "images"),os.path.join(VOCrootpath, "test", "images"),os.path.join(VOCrootpath, "train", "labels"),os.path.join(VOCrootpath, "val", "labels"), ]for imagespath in [needPath[1], needPath[3], needPath[4]]:allfiles = listPathAllfiles(imagespath)fatherpath = os.path.dirname(imagespath)txtname = os.path.basename(fatherpath)f = open(os.path.join(VOCrootpath, txtname + ".txt"), "w", encoding="utf-8")allfiles = list(map(lambda x: x.replace("\\", "/"), allfiles))f.write("\n".join(allfiles))f.close()print(imagespath, "图片数量", len(allfiles))

E:\WIIDERFACE\WIDER_VOC\train\images 图片数量 12880
E:\WIIDERFACE\WIDER_VOC\val\images 图片数量 3226
E:\WIIDERFACE\WIDER_VOC\test\images 图片数量 16097

YOLOv5训练

写数据yaml文件,下载权重文件:

path: E:\WIIDERFACE\WIDER_VOC  # dataset root dir
train: train.txt  # train images (relative to 'path') 118287 images
val: val.txt  # val images (relative to 'path') 5000 images
test: test.txt  # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794# Classes
nc: 1  # number of classes
names: ['face']  # class names

训练:

python train.py --batch-size 4 --data widerFace.yaml --img 640 --epochs 10 --weight weights/yolov5m.pt 

看到这个样子就行:

检查yolo labels对不对

import osimport cv2
import matplotlib.pyplot as plt
import numpy as npASSETS_DIRECTORY = "assets"
plt.rcParams["savefig.bbox"] = "tight"def listPathAllfiles(dirname):result = []for maindir, subdir, file_name_list in os.walk(dirname):for filename in file_name_list:apath = os.path.join(maindir, filename)result.append(apath)return resultif __name__ == '__main__':labelspath = r'E:\WIIDERFACE\WIDER_VOC\train\labels'imagespath = r'E:\WIIDERFACE\WIDER_VOC\train\images'labelsFiles = listPathAllfiles(labelspath)for lbf in labelsFiles:labels = open(lbf, "r").readlines()labels = list(map(lambda x: x.strip().split(" "), labels))imgfileName = os.path.join(imagespath, os.path.basename(lbf)[:-4] + ".jpg")img = cv2.imdecode(np.fromfile(imgfileName, dtype=np.uint8), 1)  # img是矩阵for lbs in labels:lb = list(map(float, lbs))[1:]x1 = int((lb[0] - lb[2] / 2) * img.shape[1])y1 = int((lb[1] - lb[3] / 2) * img.shape[0])x2 = int((lb[0] + lb[2] / 2) * img.shape[1])y2 = int((lb[1] + lb[3] / 2) * img.shape[0])cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 5)cv2.imshow("1", img)cv2.waitKey()cv2.destroyAllWindows()

并行训练

python -m torch.distributed.launch --nproc_per_node 4 train.py --batch-size 128 --data widerFace.yaml --img 640 --epochs 400 --weight weights/yolov5m.pt  --device 0,1,2,3

【深度学习】【Python】【Widerface数据集】 转VOC格式,VOC 转YOLOv5格式,YOLOv5训练WiderFace数据集,检查yolo labels对不对相关推荐

  1. python 动物分类_《python深度学习》笔记---5.3-1、猫狗分类(使用预训练网络)

    <python深度学习>笔记---5.3-1.猫狗分类(使用预训练网络) 一.总结 一句话总结: [小型图像数据集]:想要将深度学习应用于小型图像数据集,一种常用且非常高效的方法是使用预训 ...

  2. 深度学习小技巧(二):如何保存和恢复scikit-learn训练的模型

    深度学习小技巧(一):如何保存和恢复TensorFlow训练的模型 在许多情况下,在使用scikit学习库的同时,你需要将预测模型保存到文件中,然后在使用它们的时候还原它们,以便重复使用以前的工作.比 ...

  3. 深度学习之数据处理——如何将图片和标签打乱并划分为训练集和测试集

    深度学习之数据处理--如何将图片和标签打乱并划分为训练集和测试集 记录我的第一篇CSDN博客 最近我在网上找到Office31数据集,这个数据集中包含了三个子数据集,分别为:Amazon.dslr.w ...

  4. 阿里云深度学习实验室(DL-Lab) -- 基于Docker和EGS一键创建高性能Tensorflow分布式训练

    原文链接:点击打开链接 摘要: ## 一. 概述 Tensorflow是目前使用最为广泛的深度学习框架之一,但是目前搭建分布式多机多卡训练比较困难,而且Tensorflow原生的分布式的性能很差. 为 ...

  5. 4.keras实现--生成式深度学习之用变分自编码器VAE生成图像(mnist数据集和名人头像数据集)...

    1.VAE和GAN 变分自编码器(VAE,variatinal autoencoder)   VS    生成式对抗网络(GAN,generative adversarial network) 两者不 ...

  6. 深度学习和目标检测系列教程 17-300: 3 个类别面罩检测类别数据集训练yolov5s模型

    @Author:Runsen YOLO 是目前最火爆的的计算机视觉算法之一,今天使用的数据集来源:https://www.kaggle.com/andrewmvd/face-mask-detectio ...

  7. 最简单深度学习Python实现(二分类问题)

    二分类问题指的是所有数据的标签就只有两种,正面或者负面. 一,准备数据 我们使用的数据是内置于Keras的IMDB数据集.它包含50000条两极分化的电影评论,正面评论和负面评论各占一半.其中2500 ...

  8. 百度飞桨深度学习Python小白逆袭大神7日结营心得

    很有幸参加了百度飞桨的Python小白逆袭大神7天打卡营.七天的学习已经接近了尾声.现在回顾一下这次的课程,收获颇丰.相信很多参加的学员都感受颇丰,从小白入门到自主大作业完成,我们不仅了解了深度学习的 ...

  9. 建议收藏!耗时3个月收集的机器学习+深度学习+Python资料教程~免费分享了

    2019年,IT寒冬来势汹汹,许多IT从业者遭遇降薪.裁员.找工作难等问题,在即将到来的2020年形势依然不容乐观. 程序员作为曾经备受羡慕的高薪群体,如今也面临着"保饭碗"的巨大 ...

最新文章

  1. spring根据名称获取bean_带你从零开始手写 spring ioc 框架,深入学习 spring 源码
  2. 【126】TensorFlow 使用皮尔逊相关系数找出和标签相关性最大的特征值
  3. java 导出pdf_一次java导出pdf的经历
  4. windows设置自动清理log
  5. LeetCode 1909. 删除一个元素使数组严格递增
  6. Expression Blend 2 September Preview is now available!(中文版)
  7. 【Todo】【读书笔记】Linux高性能服务器编程
  8. Linux企业级项目实践之网络爬虫(29)——遵守robots.txt
  9. java字符串不足后面补0,JAVA字符串格式化长度不足补0
  10. matlab中garchred是什么意思,garch模型matlab
  11. Supervisor进程管理详解
  12. 2022-2027年中国海参行业市场深度分析及投资战略规划报告
  13. 安全、智慧是 Oppo 快充技术最新的发展方向
  14. php当月1号怎么获取,php获取下月1号和月底最后一天的时间
  15. 手机连接投影机的步骤_手机怎么连接投影仪?这几招实用
  16. 浅谈策略交易、系统交易和程式交易
  17. 老男孩python2020年31期学习记录贴
  18. 英国情报机构授权开设“网络间谍”硕士专业!
  19. 企业wifi管家带来无限商机,你看到了吗?
  20. Kettle使用笔记

热门文章

  1. if or函数套用_Excel将IF函数和OR函数结合使用进行多条件的选择性判断
  2. 刷屏的Google Pay:羊毛是你的,你是我的
  3. Typescript 史上最强学习入门文章 ( 2w 字)
  4. Cmake 命令语句(一)
  5. php购物车订单业务逻辑,购物车业务逻辑
  6. 【通俗向】假设检验(三):卡方检验和t检验
  7. Revit二次开发 外部命令和外部应用
  8. 捕获SQLIntegrityConstraintViolationException
  9. 模块“DAO350.DLL”可能与你正在运行的windows版本不兼容
  10. 抖音html数字9,抖音687是什么意思