基于PaddleDetection行车检测

效果展示:数据集检测精度和召回率要明显高于真实场景下的检测,尤其是召回率。因此在行车检测任务上,模型对视角的依赖程度仍然很大,对图像中的语义信息学习不够。

数据集视角检测:



真实场景检测:



一、项目简介

本项目使用paddledetection模型库实现机动车车道和周围行驶车辆的目标检测任务,使用YoLov3模型配合多种训练策略和模型压缩手段实现高精度的车辆检测。
本项目着眼于自动驾驶场景,具有十分重要的应用价值!

二、数据集介绍

本项目使用 UA-DETRAC 数据集,UA-DETRAC是车辆检测和跟踪的大规模数据集,数据集主要拍摄于北京和天津的道路过街天桥(京津冀场景),并手动标注了 8250 个车辆 和 121万目标对象外框。车辆分为四类,即轿车、公共汽车、厢式货车和其他车辆。天气情况分为四类,即多云、夜间、晴天和雨天。因此本项目是一个具有挑战性的真实多目标检测和多目标跟踪基准。该数据集包括在中国北京和天津的24个不同地点使用Cannon EOS 550D摄像机捕获的10个小时视频,视频以每秒 25 帧 (fps) 的速度录制,分辨率为 960×540 像素。

下载地址:

链接:https://pan.baidu.com/s/1s_cXIVkrlKM-96ou7K_JdQ

提取码:aq0r

三、技术路线

1、PaddleDetection简介:

PaddleDetection是飞桨推出的端到端目标检测开发套件,旨在帮助开发者更快更好地完成检测模型的训练、精度速度优化到部署全流程。PaddleDetection以模块化的设计实现了多种主流目标检测算法,并且提供了丰富的数据增强、网络组件、损失函数等模块,集成了模型压缩和跨平台高性能部署能力。目前基于PaddleDetection已经完成落地的项目涉及工业质检、遥感图像检测、无人巡检等多个领域。

PaddleDetection模块式地提供YOLOv3,EfficientDet等10余种目标检测算法、ResNet-vd,MobileNetV3等10余种backbone,以及sync batch norm, IoU Loss、可变性卷积等多个扩展模块,这些模块可以定制化地自由组合,灵活配置;同时预置提供100余种训练好的检测模型。

在YOLOv3系列模型上,通过一键式剪裁+蒸馏的方案,YOLOv3_MobileNetV1剪裁了近70%的计算量,在精度基本无损或略有提升的情况,模型在高通855芯片上加速2.3倍,GPU上也有60%的加速;YOLOv3-ResNet50vd-DCN剪裁模型,精度提升了0.6,GPU上加速20%。同时,对应压缩后的模型、压缩脚本和操作方法均可以在Github上获取。




车辆 目标检测数据集 行车实时目标检测_深度学习


2、模型库链接:

PaddleDetection代码GitHub链接:https://github.com/PaddlePaddle/PaddleDetection

PaddleDetection代码Gitee链接:https://gitee.com/paddlepaddle/PaddleDetection

PaddleDetection文档链接:https://paddledetection.readthedocs.io/

四、模型介绍

YOLOv3原版

论文地址:https://arxiv.org/abs/1804.02767



车辆 目标检测数据集 行车实时目标检测_计算机视觉_02



YOLOv3-SPP-ultralytics

  • 特征融合:大大提高小物体检测的精度。多尺度特征融合,三种尺度的特征图,每种尺度三组anchor。
  • 更换了更有效的backbone,也就是DarkNet-53


车辆 目标检测数据集 行车实时目标检测_深度学习_03


  • 正负样本分配:首先计算三种anchor模板与GT的IOU,找到大于阈值的那些anchor比如AT2,然后将GT映射到特征图尺寸,GT中心落到哪个cell,这个cell的AT2就作为正样本,计算出每个anchor的监督值,然后就可以求loss了。注意为了扩充正样本,一个GT不一定只有一个正样本,可能是1-3个。
  • u版YOLO V3提高了性能,具体来说,包括在第一个Convolutional set之后引入了SPP模块。


车辆 目标检测数据集 行车实时目标检测_计算机视觉_04


  • loss
  • 车辆 目标检测数据集 行车实时目标检测_深度学习_05


其中,置信度损失和类别损失都是用BCEloss,BCE loss对于输入进行sigmoid处理,而不是softmax,因此使用二值交叉熵的话,输入的想阿玲元素之和不一定是1,也就是不会互相抑制。置信度的监督可以是预测框和GT的IOU,也可以是0/1。定位损失使用IOU loss,IOU loss当预测框和GT不相交时,loss不变,无法收敛,GIOU解决了这个问题,但是训练收敛很慢。DIOU loss直接收敛预测框和GT中心的距离,加快了收敛,CIOU加入了长宽比的回归。


YOLOv3增强模型:

  • backbone: 将YOLOv3骨架网络更换为ResNet50-VD。ResNet50-VD网络相比原生的DarkNet53网络在速度和精度上都有一定的优势,且相较DarkNet53 ResNet系列更容易扩展,针对自己业务场景可以选择ResNet18、34、101等不同结构作为检测模型的主干网络。
  • DCNv2: 引入Deformable Convolution v2(可变形卷积)替代原始卷积操作,Deformable Convolution已经在多个视觉任务中广泛验证过其效果,在Yolo v3增强模型中考虑到速度与精度的平衡,我们仅使用Deformable Convolution替换了主干网络中Stage5部分的3x3卷积。
  • DropBlock: 在FPN部分增加DropBlock模块,提高模型泛化能力。Dropout操作如下图(b)中所示是分类网络中广泛使用的增强模型泛化能力的重要手段之一。DropBlock算法相比于Dropout算法,在Drop特征的时候会集中Drop掉某一块区域,更适应于在检测任务中提高网络泛化能力。
  • IOU Loss: 增加IoU Loss分支,可以一定程度上提高BBox定位精度,缩小一阶段和两阶段检测网络的差距。
  • 预训练模型: 使用Object365数据集训练得到的模型作为coco数据集上的预训练模型,Object365数据集包含约60万张图片以及365种类别,相比coco数据集进行预训练可以进一步提高YOLOv3的精度。

五、环境配置

# 克隆paddledetection仓库
# gitee 国内下载比较快
!git clone https://gitee.com/paddlepaddle/PaddleDetection.git

# github 
# !git clone https://github.com/PaddlePaddle/PaddleDetection.git
Cloning into 'PaddleDetection'...
remote: Enumerating objects: 25252, done.[K
remote: Counting objects: 100% (5722/5722), done.[K
remote: Compressing objects: 100% (2478/2478), done.[K
remote: Total 25252 (delta 4224), reused 4441 (delta 3233), pack-reused 19530[K
Receiving objects: 100% (25252/25252), 266.34 MiB | 17.63 MiB/s, done.
Resolving deltas: 100% (18773/18773), done.
Checking connectivity... done.
# 导入package
!pip install -r ~/PaddleDetection/requirements.txt
# 继续安装依赖库
!python3 setup.py install

六、数据准备

  • 使用UA-DETRAC数据集,将原数据集提供的标注文件转化成VOC2007的xml文件格式,方便导入模型训练
  • 训练所需文件:label.txt(保存图片目标的类别,不包括背景类)和train_list.txt、val_list.txt(保存训练/测试所需的图片和标注文件的相对路径)
# 将VOC2012数据集解压至相关文件夹中
!unzip -oq /home/aistudio/data/data36468/VOC2007.zip -d PaddleDetection/dataset
import paddle
print(paddle.is_compiled_with_cuda())
True
# 查看数据集数量
import os
os.chdir('PaddleDetection/dataset')
imgs = os.listdir('./VOC2007/JPEGImages')
print('数据集图片总量: {}'.format(len(imgs)))

def count_from_txt(path):
    with open(path, 'r') as f:
        line = f.readlines()
    return len(line)

# 各种图片的数量
img_dirs = './VOC2007/ImageSets/Main'
for img_dir in os.listdir(img_dirs):
    if img_dir[-3:] == 'txt':
        print("{}数量为: {}".format(img_dir, count_from_txt(os.path.join(img_dirs, img_dir))))
数据集图片总量: 82085
trainval.txt数量为: 65668
val.txt数量为: 9851
train.txt数量为: 55817
test.txt数量为: 16417
  • 从上面代码的运行结果可以看到,训练集包括55817张图片,验证集包括9851张图片,测试集包括16417张图片,总共82085张
  • 该项目中为最大限度的利用已标注数据,提高模型的性能,使用72234张图片训练模型,使用9851张监控模型的性能趋势
  • XML文件的格式为:
  • 车辆 目标检测数据集 行车实时目标检测_人工智能_06

# 生成train_list.txt和val_list.txt, 由于不需要比赛,这是就不生成test.txt了
with open('./VOC2007/train_list.txt', 'w') as train:
    with open(os.path.join(img_dirs, 'train.txt'), 'r') as f1:
        for line in f1.readlines():
            train.write("JPEGImages/" + line[:-1] + ".jpg" + " " + "Annotations/" + line[:-1] + ".xml\n")

with open('./VOC2007/val_list.txt', 'w') as train:
    with open(os.path.join(img_dirs, 'val.txt'), 'r') as f:
        for line in f.readlines():
            train.write("JPEGImages/" + line[:-1] + ".jpg" + " " + "Annotations/" + line[:-1] + ".xml\n")
# 制作lable.txt文件,需要读取每个图片的xml文件
# 先对9851张val来测试
import xml.etree.ElementTree as ET
os.chdir('/home/aistudio/PaddleDetection/dataset')
cats = set()
xml_path = './VOC2007/Annotations'
for xml in os.listdir(xml_path):
    if xml[-3:] != 'xml':
        continue
    full_path = os.path.join(xml_path, xml)
    tree = ET.parse(full_path)
    cls = tree.findall('object')
    for c in cls:
        cats.add(c.find('name').text)

print(cats)
{'others', 'bus', 'van', 'car'}
  • 运行上面代码可以得到数据集中所有目标总共有四类:bus,car,van,others

七、数据预处理

  • MixupImage():随机选择图像进行图像融合。
  • RandomDistort():以一定的概率对图像进行随机像素内容变换,可包括亮度、对比度、饱和度、色相角度、通道顺序的调整,模型训练时的数据增强操作。
  • RandomExpand():随机扩张图像,模型训练时的数据增强操作。
  • RandomCrop():随机裁剪图像。
  • Resize(target_size=608, interp=‘RANDOM’):将图片尺寸处理为608,插值方式为随机插值
  • RandomHorizontalFlip():实现图像的随机水平翻转
  • Normalize():图像归一化,均值默认为[0.485, 0.456, 0.406]。长度应与图像通道数量相同。标准差默认为[0.229, 0.224, 0.225]。长度应与图像通道数量相同

八、利用k-means聚类计算九个先验锚框

# 首先使用K-means计算最适合的anchors大小

# 由于voc数据集的标注文件都是xml格式的,因此使用ET模块解析xml标注文件
import xml.etree.ElementTree as ET
import numpy as np

tar_size = 608

# 重新处理每个图像中所有锚框的宽高
def load_one_info(name):

    filename = os.path.join(base, 'Annotations', name)

    tree = ET.parse(filename)
    size = tree.find('size')
    width = float(size.find('width').text)
    height = float(size.find('height').text)
    ratio = min(tar_size / width, tar_size / height)

    Objects = tree.findall('object')
    # 确定图像中有多少个目标
    objs_num = len(Objects)
    # 初始化每个目标的锚框,初始化为零
    Boxes = np.zeros((objs_num, 4), dtype=np.float32)
    # 初始化图像的类别标签
    True_classes = np.zeros((objs_num), dtype=np.float32)
    
    result = []
    for i, obj in enumerate(Objects):

        bbox = obj.find('bndbox')

        # 计算每个锚框的坐标
        x_min = float(bbox.find('xmin').text) - 1
        y_min = float(bbox.find('ymin').text) - 1
        x_max = float(bbox.find('xmax').text) - 1
        y_max = float(bbox.find('ymax').text) - 1

        # 由于图像进行了resize,这里需要重新计算改变之后的锚框的位置
        w = ratio * (x_max - x_min)
        h = ratio * (y_max - y_min)
        # 这个函数返回的是锚框的宽和高,就是为了处理锚框在resize后的大小
        result.append([w, h])

    return result
def iou(box, clusters):
    """
    计算锚框box与每个簇心的交并比
    """
    x = np.minimum(clusters[:, 0], box[0])
    y = np.minimum(clusters[:, 1], box[1])
    if np.count_nonzero(x == 0) > 0 or np.count_nonzero(y == 0) > 0:
        return 0
        raise ValueError("Box has no area")

    # 计算锚框的面积、簇心的面积和交集的面积
    intersection = x * y
    box_area = box[0] * box[1]
    cluster_area = clusters[:, 0] * clusters[:, 1]

    # 计算交并比
    iou_ = np.true_divide(intersection, box_area +
                          cluster_area - intersection + 1e-10)
    # iou_ = intersection / (box_area + cluster_area - intersection + 1e-10)

    return iou_


def avg_iou(boxes, clusters):
    # 计算所有锚框交并比的平均值
    return np.mean([np.max(iou(boxes[i], clusters)) for i in range(boxes.shape[0])])


def translate_boxes(boxes):

    new_boxes = boxes.copy()
    for row in range(new_boxes.shape[0]):
        new_boxes[row][2] = np.abs(new_boxes[row][2] - new_boxes[row][0])
        new_boxes[row][3] = np.abs(new_boxes[row][3] - new_boxes[row][1])
    return np.delete(new_boxes, [0, 1], axis=1)


def kmeans(boxes, k, dist=np.median):
    # 计算总共有多少个锚框(40138个)
    rows = boxes.shape[0]
    # 产生一个rows行,k列的随机未初始化的数组
    distances = np.empty((rows, k))
    # 产生一个全零向量
    last_clusters = np.zeros((rows,))
    # 随机种子(并未设置种子,因此此行代码不起作用)
    np.random.seed()

    # 从0-rows中随机选择k个数字,不允许相同,然后这个k个数字作为索引对应的锚框选出来存入clusters数组作为初始簇心
    clusters = boxes[np.random.choice(rows, k, replace=False)]

    while True:
        for row in range(rows):
            # 遍历每一个锚框与每个簇心的iou存入distances
            distances[row] = 1 - iou(boxes[row], clusters)

        # 计算出每个锚框最接近的簇心的序号(0-8)并存入一维数组(40138个)
        nearest_clusters = np.argmin(distances, axis=1)
        # 如果每个锚框所属的簇不发生变化,那么停止迭代
        if (last_clusters == nearest_clusters).all():
            break

        # 否则需要继续更新簇心
        for cluster in range(k):
            # 将所有属于某一个簇的锚框的下标都找到,计算这些锚框的中心点得到新的簇心
            clusters[cluster] = dist(boxes[nearest_clusters == cluster], axis=0)

        # 更新目前每个锚框所属于的簇
        last_clusters = nearest_clusters

    return clusters


def get_kmeans(anno, cluster_num=9):
    # 计算出聚类之后的簇心
    anchors = kmeans(anno, cluster_num)
    # 计算簇心的平均交并比
    ave_iou = avg_iou(anno, anchors)

    anchors = anchors.astype('int').tolist()
    # 按照锚框的面积对锚框排序
    anchors = sorted(anchors, key=lambda x: x[0] * x[1])

    return anchors, ave_iou
# 通过k-means聚类计算最适合的anchor尺寸(九个簇的中心)
result = []  # 存储每个图像所有anchor宽高的集合(每个图像可能包含若干个二维数组)
base = 'PaddleDetection/dataset/VOC2007'
for name in os.listdir(os.path.join(base, 'Annotations')):
    if name == ".ipynb_checkpoints":
        continue
    result.extend(load_one_info(name))

result = np.array(result)
# 聚类计算九个簇的中心和平均iou
anchors, ave_iou = get_kmeans(result, 9)

anchor_string = ''
anchor_sizes = []
# 打印聚类得到的锚框簇心(共九个)
for anchor in anchors:
    anchor_string += '{},{}, '.format(anchor[0], anchor[1])
    anchor_sizes.append([anchor[0], anchor[1]])
anchor_string = anchor_string[:-2]

print('anchors are:')
print(anchor_string)
print('the average iou is:')
print(ave_iou)

九、模型训练

1、YOLOv3的参数说明:

  • num_classes (int): 类别数。默认为80。
  • backbone (str): YOLOv3的backbone网络,取值范围为[‘DarkNet53’, ‘ResNet34’, ‘MobileNetV1’, ‘MobileNetV3_large’]。默认为’MobileNetV1’。
  • anchors (list|tuple): anchor框的宽度和高度,为None时表示使用默认值 [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]]。
  • anchor_masks (list|tuple): 在计算YOLOv3损失时,使用anchor的mask索引,为None时表示使用默认值 [[6, 7, 8], [3, 4, 5], [0, 1, 2]]。
  • ignore_threshold (float): 在计算YOLOv3损失时,IoU大于ignore_threshold的预测框的置信度被忽略。默认为0.7。
  • nms_score_threshold (float): 检测框的置信度得分阈值,置信度得分低于阈值的框应该被忽略。默认为0.01。
  • nms_topk (int): 进行NMS时,根据置信度保留的最大检测框数。默认为1000。
  • nms_keep_topk (int): 进行NMS后,每个图像要保留的总检测框数。默认为100。
  • nms_iou_threshold (float): 进行NMS时,用于剔除检测框IOU的阈值。默认为0.45。
  • label_smooth (bool): 是否使用label smooth。默认值为False。
  • train_random_shapes (list|tuple): 训练时从列表中随机选择图像大小。默认值为[320, 352, 384, 416, 448, 480, 512, 544, 576, 608]。

2、YOLOv3模型train接口的参数说明:

  • num_epochs (int): 训练迭代轮数。
  • train_dataset (paddlex.datasets): 训练数据读取器。
  • train_batch_size (int): 训练数据batch大小。目前检测仅支持单卡评估,训练数据batch大小与显卡数量之商为验证数据batch大小。默认值为8。
  • eval_dataset (paddlex.datasets): 验证数据读取器。
  • save_interval_epochs (int): 模型保存间隔(单位:迭代轮数)。默认为20。
  • log_interval_steps (int): 训练日志输出间隔(单位:迭代次数)。默认为2。
  • save_dir (str): 模型保存路径。默认值为’output’。
  • pretrain_weights (str): 若指定为路径时,则加载路径下预训练模型;若为字符串’IMAGENET’,则自动下载在ImageNet图片数据上预训练的模型权重;若为字符串’COCO’,则自动下载在COCO数据集上预训练的模型权重;若为None,则不使用预训练模型。默认为’IMAGENET’。
  • optimizer (paddle.fluid.optimizer): 优化器。当该参数为None时,使用默认优化器:fluid.layers.piecewise_decay衰减策略,fluid.optimizer.Momentum优化方法。
  • learning_rate (float): 默认优化器的学习率。默认为1.0/8000。
  • warmup_steps (int): 默认优化器进行warmup过程的步数。默认为1000。
  • warmup_start_lr (int): 默认优化器warmup的起始学习率。默认为0.0。
  • lr_decay_epochs (list): 默认优化器的学习率衰减轮数。默认为[213, 240]。
  • lr_decay_gamma (float): 默认优化器的学习率衰减率。默认为0.1。
  • metric (bool): 训练过程中评估的方式,取值范围为[’COCO’, ‘VOC’]。默认值为None。
  • use_vdl (bool): 是否使用VisualDL进行可视化。默认值为False。
  • sensitivities_file (str): 若指定为路径时,则加载路径下敏感度信息进行裁剪;若为字符串’DEFAULT’,则自动下载在PascalVOC数据上获得的敏感度信息进行裁剪;若为None,则不进行裁剪。默认为None。
  • eval_metric_loss (float): 可容忍的精度损失。默认为0.05。
  • early_stop (bool): 是否使用提前终止训练策略。默认值为False。
  • early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在early_stop_patience个epoch内连续下降或持平,则终止训练。默认值为5。
  • resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径。若为None,则不会恢复训练。默认值为None。
  • use_ema (bool): 是否使用指数衰减计算参数的滑动平均值。默认值为True。
  • ema_decay (float): 指数衰减率。默认值为0.9998。

3、配置文件说明

我们的数据是VOC格式的,但是配置文件中使用的是COCO格式的,我们需要更改配置文件。

我们需要用到的配置文件有四个

PaddleDetection/configs/datasets/coco_detection.yml

PaddleDetection/configs/yolov3/yolov3_r50vd_dcn_270e_coco.yml

PaddleDetection/configs/yolov3/_base_/yolov3_r50vd_dcn.yml

PaddleDetection/configs/runtime.yml

  • 更改coco_detection.yml
metric: VOC
num_classes: 4

TrainDataset:
!VOCDataSet
    dataset_dir: dataset/VOC2007
    anno_path: train_list.txt
    label_list: label.txt
    data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult']

EvalDataset:
!VOCDataSet
    dataset_dir: dataset/VOC2007
    anno_path: val_list.txt
    label_list: label.txt
    data_fields: ['image', 'gt_bbox', 'gt_class', 'difficult']

TestDataset:
  !ImageFolder
    anno_path: dataset/VOC2007/label.txt
  • 更改yolov3_r50vd_dcn_270e_coco.yml
snapshot_epoch: 1
weights: output/yolov3_r50vd_dcn_270e_coco/model_final
  • 更改yolov3_r50vd_dcn.yml
YOLOv3Head:
  anchors: [[16, 13], [22, 18], [29, 23],
            [41, 29], [65, 32], [51, 47],
            [88, 45], [94, 70], [153, 95]]
  anchor_masks: [[6, 7, 8], [3, 4, 5], [0, 1, 2]]
  loss: YOLOv3Loss
  • 更改runtime.yml
use_gpu: true
log_iter: 20
save_dir: output
snapshot_epoch: 1
  • 开启训练
%cd ~/PaddleDetection
!python tools/train.py --use_vdl true --eval -r ./output/yolov3_r50vd_dcn_270e_coco/6.pdparams \
-c configs/yolov3/yolov3_r50vd_dcn_270e_coco.yml \
-o num_calsses=4 \
-o epoch=70
%cd ~/PaddleDetection
!python tools/train.py --use_vdl true --eval -r ./output/yolov3_r50vd_dcn_270e_coco/18.pdparams \
-c configs/yolov3/yolov3_r50vd_dcn_270e_coco.yml \
-o num_calsses=4 \
-o epoch=25

十、模型评估

  • 训练25个epoch,最终模型的mIOU为90.69%

ppdet.metrics.metrics INFO: mAP(0.50, 11point) = 90.69%

ppdet.engine INFO: Total sample number: 9851, averge FPS: 19.1

# 评估 默认使用训练过程中保存的best_model
# -c 参数表示指定使用哪个配置文件
# -o 参数表示指定配置文件中的全局变量(覆盖配置文件中的设置),需使用单卡评估

!python tools/eval.py -c configs/yolov3/yolov3_r50vd_dcn_270e_coco.yml \
-o weights= /output/yolov3_r50vd_dcn_270e_coco/best_model.pdparams \
-o use_gpu=true
# 生成测试图片集合
import shutil
import os
for item in range(1, 2030):
    src = '/home/aistudio/PaddleDetection/dataset/VOC2007/JPEGImages/MVI_40752__img{:0>5d}.jpg'.format(item)
    dst = '/home/aistudio/work/test_imgs/MVI_40752__img{:0>5d}.jpg'.format(item)
    if os.path.exists(src):
        shutil.copy(src, dst)
# 如需要将视频切分成图片,请使用这段代码
import cv2  
 
# load video from your path
vc = cv2.VideoCapture('/home/aistudio/work/伦敦交通_高清 720P.mp4') 
c = 0 # start id
rval=vc.isOpened()  

while rval:    
    c = c + 1  
    rval, frame = vc.read()  
    if rval:  
        cv2.imwrite('/home/aistudio/work/new_test/'+str(c) + '.jpg', frame) 
    else:  
        break  
print(c)
vc.release()
2628
# 测试 -c 参数表示指定使用哪个配置文件
# -o 参数表示指定配置文件中的全局变量(覆盖配置文件中的设置)
# --infer_dir 参数指定预测图像所在文件夹路径
# --infer_img 参数指定预测图像路径
# --output_dir 输出结果文件夹路径
# 预测结束后会在output文件夹中生成一张画有预测结果的同名图像
%cd ~/PaddleDetection
!python tools/infer.py -c configs/yolov3/yolov3_r50vd_dcn_270e_coco.yml \
--infer_dir=/home/aistudio/work/new_test/ \
--output_dir=/home/aistudio/work/new_ret \
-o use_gpu=true \
-o weights=/home/aistudio/PaddleDetection/output/yolov3_r50vd_dcn_270e_coco/best_model.pdparams
# 此处给出手动可视化处理示例(paddledetection也提供了infer脚本)
# 就是对预测结果result的解析
import cv2
import time
import matplotlib.pyplot as plt
%matplotlib inline
model = pdx.load_model('./outputs/best_model')
image_name = '/work/test_images/test3.jpg'
# 计算目标检测的时间
start = time.time()
# 预测结果
result = model.predict(image_name, eval_trans)

print('infer time:{:.6f}s'.format(time.time()-start))
# 检测到的目标的数量
print('detected num:', len(result))

# 将预测结果进行可视化
pdx.det.visualize(image_name, result, threshold=0.5, save_dir='./')
# 图像分辨率为(1280, 720)

# 读入图像信息
im = cv2.imread(image_name)
print(im.shape)
font = cv2.FONT_HERSHEY_SIMPLEX
threshold = 0.5

# 完成对图像中目标的手动标注
for value in result:
    xmin, ymin, w, h = np.array(value['bbox']).astype(np.int)
    cls = value['category']
    score = value['score']
    # print(score)
    # 置信度小于阈值的不标注
    if score < threshold:
        continue
    # 画出锚框
    cv2.rectangle(im, (xmin, ymin), (xmin+w, ymin+h), (0, 180, 0), 2)
    cv2.putText(im, '{:s} {:.3f}'.format(cls, score),
                    (xmin, ymin), font, 0.5, (0, 0, 255), thickness=2)

cv2.imwrite('result.jpg', im)
plt.figure(figsize=(15,12))
plt.imshow(im[:, :, [2,1,0]])
plt.show()

十一、效果展示

# 检测结果生成视频(如无法运行请在本地运行)
import cv2
import os
import matplotlib.pyplot as plt
%matplotlib inline
from PIL import Image
import numpy as np
size = (1280, 720)
# 分割结果
# 完成写入对象的创建,第一个参数是合成之后的视频的名称,第二个参数是可以使用的编码器,第三个参数是帧率即每秒钟展示多少张图片,第四个参数是图片大小信息
fourcc = cv2.VideoWriter.fourcc('m', 'p', '4', 'v')
videowrite = cv2.VideoWriter('./newdet_yolov3.mp4', fourcc, 15, size)#15是帧数,size是图片尺寸
img_array = []
i = 0
path = '/home/aistudio/work/new_ret'
for filename in os.listdir(path):
    i += 1
    if not os.path.exists(path + '/' + str(i) + '.jpg'):
        print(path + '/' + str(i) + '.jpg is not exists!')
        continue
    img = cv2.imread(path + '/' + str(i) + '.jpg')
    if img is None:
        print(str(i) + '.jpg' + " is error!")
        continue
    img_array.append(img)
    

for i in range(len(img_array)):
    videowrite.write(img_array[i])

nt(path + '/' + str(i) + '.jpg is not exists!')
        continue
    img = cv2.imread(path + '/' + str(i) + '.jpg')
    if img is None:
        print(str(i) + '.jpg' + " is error!")
        continue
    img_array.append(img)
    

for i in range(len(img_array)):
    videowrite.write(img_array[i])

videowrite.release()

十二、项目总结

1、 使用PaddleDetection在UA-DETRAC数据集训练了增强型YOLOv3模型,并用于车辆检测;

2、为了体现模型的实用性,在不同路况,不同光照环境,不同背景和道路方向情况下采集的视频全部进行了测试;

可改进的地方:

1、 可以使用IOU aware的方式优化模型的收敛速度;

2、增强型Yolov3训练速度较慢,后处理流程繁琐,且不利于并行,这也是anchor-based检测模型的一大问题;