0

0

PPYOLO训练行人检测模型

P粉084495128

P粉084495128

发布时间:2025-07-21 17:35:41

|

997人浏览过

|

来源于php中文网

原创

该内容为软件杯百度行人跟踪赛题中行人检测模型训练项目说明,介绍借助PaddleDetection工具的实现过程。包括解压MOT20、CrowdHuman数据集,克隆PaddleDetection仓库,处理数据集格式,训练模型,以及模型导出和推理等步骤,还提及版本差异及注意事项。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

ppyolo训练行人检测模型 - php中文网

前言:

 该项目是在准备今年软件杯百度行人跟踪赛题的其中一个项目:行人检测模型的训练。借助PaddleDetection这一工具可以很大程度的减小工作量,完成最终项目。

说废话之前,先强调一点,由于在生成新版本的时候,上传有限制。所以,不能把整个项目一起上传,因此,下面在运行的时候可能会有些小问题,多加小心哦~
下面我想说点“废话”。AI项目的落地其实是一个挺复杂的过程的,需要数据集的准备、网络模型的搭建、模型的训练、最后是模型的部署,虽然罗列起来大体就只有这四个步骤,但其实每个步骤都是有很多的工作要做的,或者说在学术界都是有很多研究的。如果不是偏向于学术,而仅仅只关注于项目的落地、创意的实现,其实AI Studio是一个很不错的平台,百度飞桨推出的一些库也是很不错的,因为它们大大减小了项目部署的工作量。当然,偏向于学术,用飞桨也不错哦!咳咳咳~~~,我没在推销,我很严肃的在说。嘿嘿~~
再插一嘴:软件杯最终的项目,再过会就公开哦!

       

OpenArt
OpenArt

在线AI绘画艺术图片生成器工具

下载

 emmmmmm,还是再贴一张图片吧。

PPYOLO训练行人检测模型 - php中文网        

一、准备数据集(MOT20、CrowdHuman):

In [ ]
#!unzip -oq /home/aistudio/data/data77171/MOT20.zip!unzip -oq /home/aistudio/data/data78673/CrowedHuman.zip
   
把PaddleDetection从gitee的仓库里clone下来。不过,现在不建议git clone了。因为,我们当时使用的PaddleDetection默认使用的是静态图版,现在PaddleDetection已经更新了,默认使用的是PaddleDetection动态图版。(如果要用动态图版的,只需要在解压数据集的时候,把数据集放到dataset下面,然后后边在处理数据集的时候,路径稍微有一点点的不同)当然你也可以尝试使用该版本,不过下面的一些操作会有所一点点不同。如果你只是想安安静静的运行完该项目,得到最终训练好的网络模型的话,建议在解压好MOT20与CrowdHuman数据集之后,再使用我公开的数据集PaddleDetection_软件杯。
   
In [ ]
!git clone https://gitee.com/paddlepaddle/PaddleDetection.git -b release/2.0
   

1、CrowdHuman数据集的处理:

下面这个脚本任务是用来处理CrowdHuman数据集的。CrowdHuman中的标签信息是.odgt文件,我们需要把该数据集格式进行转换,转换成VOC格式数据集或者json格式,下面只是展示转换成VOC格式。感兴趣的小伙伴也可以尝试将其转换成json格式。(运行下面的脚本之前需要先创建一个文件夹“CrowdHuman_VOC"文件夹,并在该文件夹下创建名为“ImageSets”的文件夹。)
   
In [ ]
"""
参数:
roadimages CrowdHuman数据集中图片数据所在的根目录。
xml_save_path .odgt文件转换成xml文件后保存的位置。
感兴趣的小伙伴也可以进行尝试。
fpath 需要转换的.odgt文件。
"""from xml.dom import minidomimport cv2import osimport jsonfrom PIL import Image

roadimages = 'Images/'xml_save_path = "CrowdHuman_VOC/Annotations/train/"img_save_path = ''root_img_save = 'CrowdHuman_VOC/JPEGImages/train/'if not os.path.exists(xml_save_path):
    os.makedirs(xml_save_path)if not os.path.exists(root_img_save):
    os.makedirs(root_img_save)
    
fpath = "annotation_train.odgt"
 def load_func(fpath):
    assert os.path.exists(fpath)    with open(fpath, 'r') as fid:
        lines = fid.readlines()
    records = [json.loads(line.strip('\n')) for line in lines]    return records
train_txt = open('CrowdHuman_VOC/ImageSets/train.txt', 'w')
bbox = load_func(fpath)for i0, item0 in enumerate(bbox):    print(i0)    # 建立i0的xml tree
    ID = item0['ID']  # 得到当前图片的名字
    imagename = roadimages + ID + '.jpg'  # 当前图片的完整路径
    img_save_path = root_img_save + ID + '.jpg'
    savexml = xml_save_path + ID + '.xml'  # 生成的.xml注释的名字
    train_txt.write('{} {}\n'.format(img_save_path, savexml))    print(img_save_path, savexml)
    gtboxes = item0['gtboxes']
    img_name = ID
    floder = 'CrowdHuman'
    im = cv2.imread(imagename)
    cv2.imwrite(img_save_path, im)
    w = im.shape[1]
    h = im.shape[0]
    d = im.shape[2]
 
    doc = minidom.Document()  # 创建DOM树对象
    annotation = doc.createElement('annotation')  # 创建子节点
    doc.appendChild(annotation)  # annotation作为doc树的子节点
 
    folder = doc.createElement('folder')
    folder.appendChild(doc.createTextNode(floder))  # 文本节点作为floder的子节点
    annotation.appendChild(folder)  # folder作为annotation的子节点
 
    filename = doc.createElement('filename')
    filename.appendChild(doc.createTextNode(img_name + '.jpg'))
    annotation.appendChild(filename)

    size = doc.createElement('size')
    width = doc.createElement('width')
    width.appendChild(doc.createTextNode("%d" % w))
    size.appendChild(width)
    height = doc.createElement('height')
    height.appendChild(doc.createTextNode("%d" % h))
    size.appendChild(height)
    depth = doc.createElement('depth')
    depth.appendChild(doc.createTextNode("%d" % d))
    size.appendChild(depth)
    annotation.appendChild(size)
 
    segmented = doc.createElement('segmented')
    segmented.appendChild(doc.createTextNode("0"))
    annotation.appendChild(segmented)    
    for i1, item1 in enumerate(gtboxes):        # 提取全身框(full box)的标注
        boxs = [int(a) for a in item1['fbox']]        # 左上点长宽--->左上右下
        minx = str(boxs[0])
        miny = str(boxs[1])
        maxx = str(boxs[2] + boxs[0])
        maxy = str(boxs[3] + boxs[1])        # print(box)
        object = doc.createElement('object')
        nm = doc.createElement('name')
        nm.appendChild(doc.createTextNode('fbox'))  # 类名: fbox
        object.appendChild(nm)
        pose = doc.createElement('pose')
        pose.appendChild(doc.createTextNode("Unspecified"))        object.appendChild(pose)
        truncated = doc.createElement('truncated')
        truncated.appendChild(doc.createTextNode("1"))        object.appendChild(truncated)
        difficult = doc.createElement('difficult')
        difficult.appendChild(doc.createTextNode("0"))        object.appendChild(difficult)
        bndbox = doc.createElement('bndbox')
        xmin = doc.createElement('xmin')
        xmin.appendChild(doc.createTextNode(minx))
        bndbox.appendChild(xmin)
        ymin = doc.createElement('ymin')
        ymin.appendChild(doc.createTextNode(miny))
        bndbox.appendChild(ymin)
        xmax = doc.createElement('xmax')
        xmax.appendChild(doc.createTextNode(maxx))
        bndbox.appendChild(xmax)
        ymax = doc.createElement('ymax')
        ymax.appendChild(doc.createTextNode(maxy))
        bndbox.appendChild(ymax)        object.appendChild(bndbox)
        annotation.appendChild(object)
        savefile = open(savexml, 'w')
        savefile.write(doc.toprettyxml())
        savefile.close()
   
In [ ]
from xml.dom import minidomimport cv2import osimport jsonfrom PIL import Image

roadimages = 'Images/'xml_save_path = "CrowdHuman_VOC/Annotations/val/"img_save_path = ''root_img_save = 'CrowdHuman_VOC/JPEGImages/val/'if not os.path.exists(xml_save_path):
    os.makedirs(xml_save_path)if not os.path.exists(root_img_save):
    os.makedirs(root_img_save)
    
fpath = "annotation_val.odgt"
 def load_func(fpath):
    assert os.path.exists(fpath)    with open(fpath, 'r') as fid:
        lines = fid.readlines()
    records = [json.loads(line.strip('\n')) for line in lines]    return records
val_txt = open('CrowdHuman_VOC/ImageSets/val.txt', 'w')
bbox = load_func(fpath) 
for i0, item0 in enumerate(bbox):    print(i0)    # 建立i0的xml tree
    ID = item0['ID']  # 得到当前图片的名字
    imagename = roadimages + ID + '.jpg'  # 当前图片的完整路径
    img_save_path = root_img_save + ID + '.jpg'
    savexml = xml_save_path + ID + '.xml'  # 生成的.xml注释的名字
    val_txt.write('{} {}\n'.format(img_save_path, savexml))    print(img_save_path, savexml)
    gtboxes = item0['gtboxes']
    img_name = ID
    floder = 'CrowdHuman'
    im = cv2.imread(imagename)
    cv2.imwrite(img_save_path, im)
    w = im.shape[1]
    h = im.shape[0]
    d = im.shape[2]
 
    doc = minidom.Document()  # 创建DOM树对象
    annotation = doc.createElement('annotation')  # 创建子节点
    doc.appendChild(annotation)  # annotation作为doc树的子节点
 
    folder = doc.createElement('folder')
    folder.appendChild(doc.createTextNode(floder))  # 文本节点作为floder的子节点
    annotation.appendChild(folder)  # folder作为annotation的子节点
 
    filename = doc.createElement('filename')
    filename.appendChild(doc.createTextNode(img_name + '.jpg'))
    annotation.appendChild(filename)

    size = doc.createElement('size')
    width = doc.createElement('width')
    width.appendChild(doc.createTextNode("%d" % w))
    size.appendChild(width)
    height = doc.createElement('height')
    height.appendChild(doc.createTextNode("%d" % h))
    size.appendChild(height)
    depth = doc.createElement('depth')
    depth.appendChild(doc.createTextNode("%d" % d))
    size.appendChild(depth)
    annotation.appendChild(size)
 
    segmented = doc.createElement('segmented')
    segmented.appendChild(doc.createTextNode("0"))
    annotation.appendChild(segmented)    
    for i1, item1 in enumerate(gtboxes):        # 提取全身框(full box)的标注
        boxs = [int(a) for a in item1['fbox']]        # 左上点长宽--->左上右下
        minx = str(boxs[0])
        miny = str(boxs[1])
        maxx = str(boxs[2] + boxs[0])
        maxy = str(boxs[3] + boxs[1])        # print(box)
        object = doc.createElement('object')
        nm = doc.createElement('name')
        nm.appendChild(doc.createTextNode('fbox'))  # 类名: fbox
        object.appendChild(nm)
        pose = doc.createElement('pose')
        pose.appendChild(doc.createTextNode("Unspecified"))        object.appendChild(pose)
        truncated = doc.createElement('truncated')
        truncated.appendChild(doc.createTextNode("1"))        object.appendChild(truncated)
        difficult = doc.createElement('difficult')
        difficult.appendChild(doc.createTextNode("0"))        object.appendChild(difficult)
        bndbox = doc.createElement('bndbox')
        xmin = doc.createElement('xmin')
        xmin.appendChild(doc.createTextNode(minx))
        bndbox.appendChild(xmin)
        ymin = doc.createElement('ymin')
        ymin.appendChild(doc.createTextNode(miny))
        bndbox.appendChild(ymin)
        xmax = doc.createElement('xmax')
        xmax.appendChild(doc.createTextNode(maxx))
        bndbox.appendChild(xmax)
        ymax = doc.createElement('ymax')
        ymax.appendChild(doc.createTextNode(maxy))
        bndbox.appendChild(ymax)        object.appendChild(bndbox)
        annotation.appendChild(object)
        savefile = open(savexml, 'w')
        savefile.write(doc.toprettyxml())
        savefile.close()
   
In [ ]
!mv CrowdHuman_VOC PaddleDetection/dataset
   
In [ ]
train_new = open('dataset/CrowdHuman_VOC/ImageSets/train_new.txt', 'w')with open('dataset/CrowdHuman_VOC/ImageSets/train.txt', 'r') as f:    for info in f.readlines():
        info_ = info.strip().split(' ')        for file_ in info_:
            result = file_.strip().split('/')
            train_new.write('{}/{}/{} '.format(result[1], result[2], result[3]))
        train_new.write('\n')
   

2、MOT20数据集的处理:

下面这个脚本是用来将MOT20数据集进行转换,转换成VOC格式的数据集。
   
In [ ]
import cv2import osimport numpy as npimport timeimport argparseimport shutilimport codecsimport progressbar

train_20 = ['MOT20/train/MOT20-01/',                'MOT20/train/MOT20-02/',                'MOT20/train/MOT20-03/',                'MOT20/train/MOT20-05/']

test_20 = ['MOT20/test/MOT20-04/',               'MOT20/test/MOT20-06/',               'MOT20/test/MOT20-07/',               'MOT20/test/MOT20-08/']def parse_ini(dir):
    ini_fp = open(dir + 'seqinfo.ini','r')
    seq_info = ini_fp.readlines()
    seqLenth = int(seq_info[4][10:])
    imWidth = int(seq_info[5][8:])
    imHeight = int(seq_info[6][9:])    return seqLenth,imWidth,imHeightdef gennerate_gt(gt,Annotation,frame,filename,width,height):
    fp_gt = open(gt)
    gt_lines = fp_gt.readlines()

    gt_fram = []    for line in gt_lines:
        fram_id = int(line.split(',')[0])        if fram_id == frame:
            visible = float(line.split(',')[8])
            label_class = line.split(',')[7]            if (label_class == '1' or label_class == '2' or label_class == '7') and visible > 0.3:
                gt_fram.append(line)    with codecs.open(Annotation + filename + '.xml', 'w') as xml:
        xml.write('\n')
        xml.write('\n')
        xml.write('\t' + 'voc' + '\n')
        xml.write('\t' + filename + '.jpg' + '\n')        # xml.write('\t' + path + "/" + info1 + '\n')
        xml.write('\t\n')
        xml.write('\t\t The MOT-Det \n')
        xml.write('\t\n')
        xml.write('\t\n')
        xml.write('\t\t' + str(width) + '\n')
        xml.write('\t\t' + str(height) + '\n')
        xml.write('\t\t' + '3' + '\n')
        xml.write('\t\n')
        xml.write('\t\t0\n')        for bbox in gt_fram:
            x1 = int(bbox.split(',')[2])
            y1 = int(bbox.split(',')[3])
            x2 = int(bbox.split(',')[4])
            y2 = int(bbox.split(',')[5])

            xml.write('\t\n')
            xml.write('\t\tperson\n')
            xml.write('\t\tUnspecified\n')
            xml.write('\t\t0\n')
            xml.write('\t\t0\n')
            xml.write('\t\t\n')
            xml.write('\t\t\t' + str(x1) + '\n')
            xml.write('\t\t\t' + str(y1) + '\n')
            xml.write('\t\t\t' + str(x1 + x2) + '\n')
            xml.write('\t\t\t' + str(y1 + y2) + '\n')
            xml.write('\t\t\n')
            xml.write('\t\n')
        xml.write('')#用于校验图片数量和标注数量是否一致def check_num(data_dir, JPEGImage_dir,Annotations_dir=None,ori_num = 0):
    num = 0
    for folder in data_dir:
        folder_len,_,_ = parse_ini(folder)
        num += folder_len
    img_list = os.listdir(JPEGImage_dir)    if ori_num==0:
        img_num = len(img_list)    else:
        img_num = len(img_list)-ori_num    # print('img_num:',img_num)
    if Annotations_dir:
        ann_list = os.listdir(Annotations_dir)
        ann_num = len(ann_list)        assert ann_num == num    assert img_num == num,'if it is the second time run this demo, please delete the JPEGImages folder and retry'
    # print('num:', num)
    print('folders {} have been succeed checked'.format(data_dir))    return numdef main():
    
    """train_dirs = train_20"""
    test_dirs = test_20

    motyear = '20'
    folder = 'MOT' + motyear + 'Det'+'/VOC/'
    Annotations = folder+'Annotations/'+'val/'
    ImageSets = folder + 'ImageSets/'
    JPEGImages = folder + 'JPEGImages/'+'val/'
    Main = ImageSets + 'Main/'
    if not os.path.exists(Annotations):
        os.makedirs(Annotations)    if not os.path.exists(ImageSets):
        os.makedirs(ImageSets)    if not os.path.exists(JPEGImages):
        os.makedirs(JPEGImages)    if not os.path.exists(Main):
        os.makedirs(Main)    #fp_txt = open(ImageSets + 'train_all.txt', 'w')
    fp_test = open(ImageSets + 'test_all.txt', 'w')    for test_ in test_dirs:
        img2 = test_ + 'img1/'
        folder_id = test_[-3:-1]
        test_list = os.listdir(img2)
        test_seqLen,_,_ = parse_ini(test_)        assert test_seqLen==len(test_list)

        bar = progressbar.ProgressBar(maxval=len(test_list)).start()
        count = 0

        for img in test_list:
            count += 1
            bar.update(count)
            format_name = folder_id + img
            fp_test.writelines(format_name[:-4] + '\n')  # 将生成的新的文件名写入train_all.txt,用于后续数据集拆分
            shutil.copy(img2 + img, JPEGImages + '/' + format_name)  # 将文件移动到指定文件夹并重新命名

    fp_test.close()if __name__ == '__main__':
    main()
   
In [1]
!pip install pycocotools
   
In [ ]
#也可以尝试把转换后的VOC格式数据集转换成coco数据集格式后再进行训练!python PaddleDetection/tools/x2coco.py \
    --dataset_type voc \
    --voc_anno_dir MOT20Det/voc/Annotations \
    --voc_anno_list MOT20Det/voc/ImageSets/valid_all.txt \
    --voc_label_list MOT20Det/voc/label_list.txt \
    --voc_out_name voc_valid.json
       
Start converting !
100%|███████████████████████████████████████| 893/893 [00:00<00:00, 2474.32it/s]
       

二、模型的训练:

In [ ]
%cd PaddleDetection/
!pip install paddledet
   
由于生成VOC数据集的脚本文件有一点小问题,所以在训练之前要先把train.txt文件最后一行删除然后再保存进行训练。
   
In [2]
#mot20!python PaddleDetection/tools/train.py \
    -c ppyolo.yml \
    --vdl_log_dir ~/log_crowdhuman/ppyolo_voc \
    --use_vdl True
   
In [ ]
!python tools/export_model.py \
    -c configs/ppyolo/ppyolov2_r50vd_dcn_365e_coco.yml\    #-o output/ppyolov2_r50vd_dcn_365e_coco/model_final.pdparams\
    --output_dir inference_model
   

三、进行推理:

In [ ]
!python tools/infer.py \
    -c configs/ppyolo/ppyolov2_r50vd_dcn_365e_coco.yml \
    -o weights=output/ppyolov2_r50vd_dcn_365e_coco/model_final.pdparams \
    --infer_img=/home/aistudio/infer_img/00016.jpg \
    --draw_threshold=0.15
   
这里我只是把PaddleDetection里的相关代码提取出来,放到文件夹里。这种方式便于部署,用起来很舒服。嘿嘿~~。
   
In [ ]
import cv2from Detector_ppyolo import Detector

img = cv2.imread('MOT20Det/VOC/JPEGImages/train/01000313.jpg')
model_dir = 'inference_model/ppyolo'config = Config(model_dir)
detector = Detector(
    config, model_dir, use_gpu=False, run_mode='fluid')
result, detections = detector.predict(img, 0.15)print(detections)
   

相关专题

更多
ip地址修改教程大全
ip地址修改教程大全

本专题整合了ip地址修改教程大全,阅读下面的文章自行寻找合适的解决教程。

86

2025.12.26

压缩文件加密教程汇总
压缩文件加密教程汇总

本专题整合了压缩文件加密教程,阅读专题下面的文章了解更多详细教程。

50

2025.12.26

wifi无ip分配
wifi无ip分配

本专题整合了wifi无ip分配相关教程,阅读专题下面的文章了解更多详细教程。

100

2025.12.26

漫蛙漫画入口网址
漫蛙漫画入口网址

本专题整合了漫蛙入口网址大全,阅读下面的文章领取更多入口。

293

2025.12.26

b站看视频入口合集
b站看视频入口合集

本专题整合了b站哔哩哔哩相关入口合集,阅读下面的文章查看更多入口。

589

2025.12.26

俄罗斯搜索引擎yandex入口汇总
俄罗斯搜索引擎yandex入口汇总

本专题整合了俄罗斯搜索引擎yandex相关入口合集,阅读下面的文章查看更多入口。

725

2025.12.26

虚拟号码教程汇总
虚拟号码教程汇总

本专题整合了虚拟号码接收验证码相关教程,阅读下面的文章了解更多详细操作。

63

2025.12.25

错误代码dns_probe_possible
错误代码dns_probe_possible

本专题整合了电脑无法打开网页显示错误代码dns_probe_possible解决方法,阅读专题下面的文章了解更多处理方案。

30

2025.12.25

网页undefined啥意思
网页undefined啥意思

本专题整合了undefined相关内容,阅读下面的文章了解更多详细内容。后续继续更新。

94

2025.12.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.6万人学习

Django 教程
Django 教程

共28课时 | 2.5万人学习

SciPy 教程
SciPy 教程

共10课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号