基于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
YOLOv3-SPP-ultralytics
- 特征融合:大大提高小物体检测的精度。多尺度特征融合,三种尺度的特征图,每种尺度三组anchor。
- 更换了更有效的backbone,也就是DarkNet-53:
- 正负样本分配:首先计算三种anchor模板与GT的IOU,找到大于阈值的那些anchor比如AT2,然后将GT映射到特征图尺寸,GT中心落到哪个cell,这个cell的AT2就作为正样本,计算出每个anchor的监督值,然后就可以求loss了。注意为了扩充正样本,一个GT不一定只有一个正样本,可能是1-3个。
- u版YOLO V3提高了性能,具体来说,包括在第一个Convolutional set之后引入了SPP模块。
- loss:
其中,置信度损失和类别损失都是用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文件的格式为:
# 生成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检测模型的一大问题;