栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

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

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

文章目录
  • 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 np


def 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:WIIDERFACEwider_face_splitwider_face_splitwider_face_train_bbx_gt.txt",
        "trainimagepath": r"E:WIIDERFACEWIDER_trainWIDER_trainimages",
        "valtxt": r"E:WIIDERFACEwider_face_splitwider_face_splitwider_face_val_bbx_gt.txt",
        "valimagepath": r"E:WIIDERFACEWIDER_valWIDER_valimages",
        "texttxt": r"E:WIIDERFACEwider_face_splitwider_face_splitwider_face_test_filelist.txt",
        "textimagepath": r"E:WIIDERFACEWIDER_testWIDER_testimages", }

    # 给出VOC数据存储地址
    VOCrootpath = r"E:WIIDERFACEWIDER_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 == "":
                    break
                im_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:
                    continue
                numbox = 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)  # 将一张图片的所有人脸数据加入bboxes

                    filename = 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 == "":
                break
            im_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:
                continue
            filename = 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 ET


def 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').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult) == 1:
            continue
        cls_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] = 0
        if b[1] > size_width:
            b[1] = size_width
        if b[2] < 0:
            b[2] = 0
        if b[3] > size_height:
            b[3] = size_height
        txt_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 1
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in txt_data]) + 'n')

    in_file.close()
    out_file.close()
    return 0


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 result


if __name__ == '__main__':
    classes = {'face': 0}  # 标签名:标签id

    # 给出VOC数据存储地址
    VOCrootpath = r"E:WIIDERFACEWIDER_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 = 0
        for xmlName in allfiles:
            # xml存储路径,yololabels存储路径,xml文件名称不带.xml后缀,需要的类及其类id的字典
            if convert_annotation(xmlpath, txtpath, os.path.basename(xmlName)[:-4], classes) == 1:
                failNum += 1
        print("失败了多少个文件的labels:", failNum)


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

C:Usersdong.xie.condaenvspy38python.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: 9

Process finished with exit code 0

数据集的imageslisttxt

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

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

import os


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 result


if __name__ == '__main__':
    classes = {'face': 0}  # 标签名:标签id

    # 给出VOC数据存储地址
    VOCrootpath = r"E:WIIDERFACEWIDER_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:WIIDERFACEWIDER_VOCtrainimages 图片数量 12880
E:WIIDERFACEWIDER_VOCvalimages 图片数量 3226
E:WIIDERFACEWIDER_VOCtestimages 图片数量 16097

YOLOv5训练

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

path: E:WIIDERFACEWIDER_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 os

import cv2
import matplotlib.pyplot as plt
import numpy as np

ASSETS_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 result


if __name__ == '__main__':
    labelspath = r'E:WIIDERFACEWIDER_VOCtrainlabels'
    imagespath = r'E:WIIDERFACEWIDER_VOCtrainimages'

    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()

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1017938.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号