CVPR 2020 多目标跟踪算法JDE 训练

数据集:

MOT17,取其中的MOT17-13-DPM,MOT17-13-FRCNN,MOT17-13-SDP三个文件夹

检测目标:

人,车,自行车,摩托车

原始数据标注:

数据处理:

(1)按照原始数据集标注,gt.txt中的倒数第三列是目标轨迹是否进入考虑范围的标志,这里将我们需要的四个类别(人,车,自行车,摩托车)的这个标志设置为1,可以用notepad++打开,查找,替换,这里以替换第三类也就是上表中的car类的标记为例,如下图:

同理,将上表中类别为4(bicycle),5(motorbike),7(static person)的标志位都设置为1。

(2)调用脚本生成JDE训练需要的如下标注格式:

这里的x_center,y_center,width,height都是经过原图宽高归一化的。

生成上面格式的脚本(修改自FairMOT中的脚本):

import os.path as osp
import os
import numpy as np
import shutil

def mkdirs(d):
    if not osp.exists(d):
        os.makedirs(d)


seq_root = 'F:/dataset/MOT/MOT17/images/train'
label_root = 'F:/dataset/MOT/JDE/labels_with_ids'
img_root="F:/dataset/MOT/JDE/images"
mkdirs(label_root)
seqs = [s for s in os.listdir(seq_root)]
seqs=["MOT17-13-DPM","MOT17-13-FRCNN","MOT17-13-SDP"]

tid_curr = 0
tid_last = -1
for seq in seqs:
    print(seq)
    seq_info = open(osp.join(seq_root, seq, 'seqinfo.ini')).read()
    seq_width = int(seq_info[seq_info.find('imWidth=') + 8:seq_info.find('\nimHeight')])
    seq_height = int(seq_info[seq_info.find('imHeight=') + 9:seq_info.find('\nimExt')])

    gt_txt = osp.join(seq_root, seq, 'gt', 'gt.txt')
    gt = np.loadtxt(gt_txt, dtype=np.float64, delimiter=',')

    seq_label_root = osp.join(label_root)
    if not os.path.exists(label_root):
        mkdirs(seq_label_root)

    for fid, tid, x, y, w, h, mark, label, _ in gt:
        label=int(label)
        print(" ",fid,label)
        if mark == 0 or (label != 1 and label!=3 and label!=4 and label!=5 and label!=7):  #只保留行人,汽车,自行车,摩托车
            #print ("imgnored label:",str(label))
            continue
        final_label=0
        if label==1 or label==7:  # Pedestrain
            final_label=0  
        if label==3:              # Car
            final_label=1
        if label==4:              # Bicycle
            final_label=2
        if label==5:              # Motorbike
            final_label=3

        fid = int(fid)
        tid = int(tid)
        if not tid == tid_last:
            tid_curr += 1
            tid_last = tid
        x += w / 2
        y += h / 2
        img_src_fpath=osp.join(seq_root,seq,"img1")
        img_fpath=osp.join(img_root, '{}_{:06d}.jpg'.format(seq,fid))
        
        label_fpath = osp.join(seq_label_root, '{}_{:06d}.txt'.format(seq,fid))
        label_str = '{:d} {:d} {:.6f} {:.6f} {:.6f} {:.6f}\n'.format(int(final_label),
            tid_curr, x / seq_width, y / seq_height, w / seq_width, h / seq_height)
        with open(label_fpath, 'a') as f:
            f.write(label_str)
        if not os.path.exists(img_fpath):
            shutil.copy(img_src_fpath+"/{:06d}.jpg".format(fid),img_fpath)

生成的数据及标注:

标注的内容:

这时可以写一个脚本显示出这些标注框,看看是否有错:

脚本:

#-*- coding:utf-8 -*-
import os
import cv2
'''
显示跟踪训练数据集标注
'''
root_path="F:/dataset/MOT/JDE"
img_dir="images"
label_dir="labels_with_ids"

imgs=os.listdir(root_path+"/"+img_dir)
for i,img in enumerate(imgs) :
    img_name=img[:-4]
    label_f=open(root_path+"/"+label_dir+"/"+img_name+".txt","r")
    lines=label_f.readlines()
    img_data=cv2.imread(root_path+"/"+img_dir+"/"+img)
    H,W,C=img_data.shape
    for line in lines:
        line_list=line.strip().split()
        class_num=int(line_list[0]) #类别号
        obj_ID=int(line_list[1])    #目标ID
        x,y,w,h=line_list[2:]       #中心坐标,宽高(经过原图宽高归一化后)
        x=int(float(x)*W)
        y=int(float(y)*H)
        w=int(float(w)*W)
        h=int(float(h)*H)
        left=int(x-w/2)
        top=int(y-h/2)
        right=left+w
        bottom=top+h
        cv2.circle(img_data,(x,y),1,(0,0,255))
        cv2.rectangle(img_data, (left,top),(right,bottom), (0,255,0), 2)
        cv2.putText(img_data, str(obj_ID), (left,top), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0,0,255), 1)
    resized_img=cv2.resize(img_data,(800,416))
    cv2.imshow("label",resized_img)
    cv2.waitKey(1)


显示标注结果:

(3)生成训练文件。

由于代码中读取训练图片和标签是通过一个xxx.train文件来读取的,形式如下:

所以写脚本,生成训练的xxx.train文件,脚本:

import os
image_flder="images"
imgs=os.listdir(image_flder)

train_f=open("jde_mot17.train","w")

for img in imgs:
    save_str=image_flder+'/'+img+"\n"
    train_f.write(save_str)

train_f.close()

生成的训练文件:

训练

修改cfg/ccmcpe.json文件:

修改数据集路径为前面生成的xxx.train文件路径:

在保存模型和配置文件之前,漏了判断文件夹是否存在的操作,会报错。

去掉中途的验证:

修改网络定义文件中分类的类别数,这里我需要分4个类:人,车,自行车,摩托车,所以设置yolo层的classes=4,此外还要将yolo层的输入层维度进行修改,这里的yolo层有两个分支的输入:(1)分类和回归分支(2)特征提取分支,而特征提取分支不因类别而改变,一直是固定的512维,不用修改。因为yolo层的输出通道数是(C+5)*A,这里的C指的是类别数,A指的是anchor的个数。这里C=4,A默认是4,所以YOLO层输入层的维度是(4+5)*4=36,修改如下:

此外还需修改YOLOlayer层的forward方法,修改如下,将原来的定值24修改成根据类别自动计算的变量split,就可以适应不同的类别数了。这个值主要是用来切分分类回归值和特征值的维度分割点,前面的split个通道是类别和坐标回归,split到最后是特征。

开始训练:

但是训练过程中出现了loss突然变很大的情况,感觉是数据哪里出了问题,标签原来作者只有行人一类,类别全部为0。

原因分析:(1)脏数据,可能是训练数据不够好,其中有些标签没处理正确。(2)数据量不够,只用了MOT中一个场景的数据。(3)仔细研究代码,看看哪里设置不正确。训练成功之后再来更新...

猜你喜欢

转载自blog.csdn.net/sinat_33486980/article/details/105684839
今日推荐