首页 PaddleX 帖子详情
PaddleX助力无人驾驶
收藏
快速回复
PaddleX 文章解决方案 2117 12
PaddleX助力无人驾驶
收藏
快速回复
PaddleX 文章解决方案 2117 12

地址:https://aistudio.baidu.com/aistudio/projectdetail/464339

工具支持: PaddleX;

平台: AI Studio

模型: YOLOv3;

数据集:UA-DETRAC 车辆检测数据集;

项目简介:

无人驾驶汽车利用传感器技术、信号处理技术、通讯技术和计算机技术等,通过集成视觉、激光雷达、超声传感器、微波雷达、GPS、里程计、磁罗盘等多种车载传感器来辨识汽车所处的环境和状态,并根据所获得的道路信息、交通信号的信息、车辆位置和障碍物信息做出分析和判断,向主控计算机发出期望控制,控制车辆转向和速度,从而实现无人驾驶车辆依据自身意图和环境的拟人驾驶。

该项目使用PaddleX提供的YOLOv3模型,在 UA-DETRAC 车辆检测数据集进行训练;

训练结果能够检测到car,van,bus等不同类型车辆,mAP为0.73;

并使用开源车道检测算法,实现了无人驾驶部分的视觉感知——车辆检测和车道线分割;

最终效果:

 

PaddleX工具简介:

PaddleX简介:PaddleX是飞桨全流程开发工具,集飞桨核心框架、模型库、工具及组件等深度学习开发所需全部能力于一身,打通深度学习开发全流程,并提供简明易懂的Python API,方便用户根据实际生产需求进行直接调用或二次开发,为开发者提供飞桨全流程开发的最佳实践。目前,该工具代码已开源于GitHub,同时可访问PaddleX在线使用文档,快速查阅读使用教程和API文档说明。

PaddleX代码GitHub链接:https://github.com/PaddlePaddle/PaddleX/tree/develop

PaddleX文档链接:https://paddlex.readthedocs.io/zh_CN/latest/index.html

PaddleX官网链接:https://www.paddlepaddle.org.cn/paddle/paddlex

 

1. 安装PaddleX库:
pip install paddlex -i https://mirror.baidu.com/pypi/simple

2. 设置工作路径,并使用0号GPU卡
import matplotlib

matplotlib.use('Agg') import os

os.environ['CUDA_VISIBLE_DEVICES'] = '0'import paddlex as pdx

 

os.chdir('/home/aistudio/work/')

2020-05-11 08:22:10,094-INFO: font search path ['/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/ttf', '/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/afm', '/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/pdfcorefonts']2020-05-11 08:22:10,546-INFO: generated new fontManager

3. 数据集:
数据集简介:

数据集使用 UA-DETRAC 数据集,是一个具有挑战性的真实多目标检测和多目标跟踪基准。

该数据集由10小时的视频组成,这些视频由中国北京和天津的24个不同地点使用Cannon EOS 550D摄像机拍摄。

视频以每秒 25 帧 (fps) 的速度录制,分辨率为 960×540 像素。

UA-DETRAC 数据集中有超过 140 000 个帧,手动标注了 8250 辆车,总共有 121 万个标记了边界框的目标。

 

4. 生成所需文件:
这里的PaddleX同时支持VOC和COCO两种格式的数据;

需要的文件有:

1. labels.txt:保存目标类别的文件,不包括背景类;

 

1. train_list.txt和val_list.txt:保存训练/测试所需的图片和标注文件的相对路径;

 

!unzip /home/aistudio/data/data34332/VOC2012.zip -d ./

 

imgs = os.listdir('./VOC2012/JPEGImages')

print('total:', len(imgs))

with open('./VOC2012/train_list.txt', 'w') as f:

    for im in imgs[:-200]:

        info = 'JPEGImages/'+im+' '

        info += 'Annotations/'+im[:-4]+'.xml\n'

        f.write(info)

with open('./VOC2012/val_list.txt', 'w') as f:

    for im in imgs[-200:]:

        info = 'JPEGImages/'+im+' '

        info += 'Annotations/'+im[:-4]+'.xml\n'

        f.write(info)

total: 6000

5.设置图像数据预处理和数据增强模块:
具体参数见:

https://paddlex.readthedocs.io/zh_CN/latest/apis/transforms/det_transforms.html

from paddlex.det import transforms

train_transforms = transforms.Compose([

    transforms.MixupImage(mixup_epoch=250),

    transforms.RandomDistort(),

    transforms.RandomExpand(),

    transforms.RandomCrop(),

    transforms.Resize(target_size=608, interp='RANDOM'),

    transforms.RandomHorizontalFlip(),

    transforms.Normalize(),

])

 

eval_transforms = transforms.Compose([

    transforms.Resize(target_size=608, interp='CUBIC'),

    transforms.Normalize(),

])

6.定义数据迭代器:
训练集总共有6000张图片;

我们选取5800训练,剩余200张进行测试;

参数

data_dir (str): 数据集所在的目录路径。

file_list (str): 描述数据集图片文件和对应标注文件的文件路径(文本内每行路径为相对data_dir的相对路径)。

label_list (str): 描述数据集包含的类别信息文件路径。

transforms (paddlex.det.transforms): 数据集中每个样本的预处理/增强算子,详见paddlex.det.transforms。

num_workers (int|str):数据集中样本在预处理过程中的线程或进程数。默认为’auto’。当设为’auto’时,根据系统的实际CPU核数设置num_workers: 如果CPU核数的一半大于8,则num_workers为8,否则为CPU核数的一半。

buffer_size (int): 数据集中样本在预处理过程中队列的缓存长度,以样本数为单位。默认为100。

parallel_method (str): 数据集中样本在预处理过程中并行处理的方式,支持’thread’线程和’process’进程两种方式。默认为’thread’(Windows和Mac下会强制使用thread,该参数无效)。

shuffle (bool): 是否需要对数据集中样本打乱顺序。默认为False。

· 

base = './VOC2012/'

 

train_dataset = pdx.datasets.VOCDetection(

    data_dir=base,

    file_list=base+'train_list.txt',

    label_list=base+'labels.txt',

    transforms=train_transforms,

    shuffle=True)

eval_dataset = pdx.datasets.VOCDetection(

    data_dir=base,

    file_list=base+'val_list.txt',

    label_list=base+'labels.txt',

    transforms=eval_transforms)

2020-05-11 07:57:15 [INFO]    Starting to read file list from dataset...2020-05-11 07:57:16 [INFO]    5800 samples in file ./VOC2012/train_list.txt

creating index...index created!2020-05-11 07:57:17 [INFO]    Starting to read file list from dataset...2020-05-11 07:57:17 [INFO]    200 samples in file ./VOC2012/val_list.txt

creating index...index created!

7. 定义YOLOv3模型并开始训练:
YOLOv3简介:
论文地址:https://arxiv.org/abs/1804.02767

‘Sometimes you just kinda phone it in for a year, you know?’

作者说他一年大部分时间去刷 Twitter 了,然后玩了(play around)一阵子 GAN;

正好剩下一点时间,就改进了一下 YOLO 算法,提出了 YOLO v3;

 

参数说明:
· 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]。

num_classes = len(train_dataset.labels)print('class num:', num_classes)

model = pdx.det.YOLOv3(num_classes=num_classes, backbone='DarkNet53')

model.train(

    num_epochs=4,

    train_dataset=train_dataset,

    train_batch_size=4,

    eval_dataset=eval_dataset,

    learning_rate=0.000125,

    lr_decay_epochs=[400, 800],

    save_interval_epochs=2,

    log_interval_steps=200,

    save_dir='./yolov3_darknet53',

    use_vdl=True)

class num: 4

2020-05-11 08:15:15 [INFO]    Load pretrain weights from ./yolov3_darknet53/pretrain/DarkNet53.2020-05-11 08:15:16 [INFO]    There are 260 varaibles in ./yolov3_darknet53/pretrain/DarkNet53 are loaded.

8. 评估模型:
使用 evaluate 方法进行模型评估;

最终mAP为0.73左右;

 

model.evaluate(eval_dataset, batch_size=1, epoch_id=None, metric=None, return_details=False)

2020-05-11 07:27:25 [INFO]    Start to evaluating(total_samples=200, total_steps=200)...

 

100%|██████████| 200/200 [00:18<00:00, 10.89it/s]

 

 

 

 

 

OrderedDict([('bbox_map', 73.14713977140035)])

9. 加载模型用于测试:
检测结果:

 

image_name = './test6.jpg'# result = model.predict(image_name)

pdx.det.visualize(image_name, result, threshold=0.5, save_dir='./output/')

10. 定义车道线检测模型:
这里使用了开源的项目:

https://github.com/Sharpiless/advanced_lane_detection

 

该车道检测算法流程为:

给定一组棋盘图像(在camera_cal文件夹内),计算相机校准矩阵和失真系数。

 

· 

根据校准矩阵和失真系数对原始图像应用失真校正。

· 

· 

使用颜色变换,渐变等创建阈值二进制图像。

· 

 

· 应用透视变换以校正二进制图像(“鸟瞰”)。

 

· 检测图像中车道像素并拟合,以找到车道边界。

 

· 将检测到的车道边界矫正到原始图像。

 

 

import numpy as npimport cv2, pickle, glob, osimport matplotlib.pyplot as pltimport matplotlib.image as mpimgimport tools

 

from moviepy.editor import VideoFileClipfrom IPython.display import HTML

class GlobalObjects:

 

    def __init__(self):

        self.__set_folders()

        self.__set_hyper_parameters()

        self.__set_perspective()

        self.__set_kernels()

        self.__set_mask_regions()

 

    def __set_folders(self):

        # Use one slash for paths.

        self.camera_cal_folder = 'camera_cal/'

        self.test_images = glob.glob('test_images/*.jpg')

        self.output_image_path = 'output_images/test_'

        self.output_movie_path = 'output_movies/done_'

 

 

    def __set_hyper_parameters(self):

        self.img_size   = (1280, 720) # (x,y) values for img size (cv2 uses this)

        self.img_shape  = (self.img_size[1], self.img_size[0]) # (y,x) As numpy spits out

        return

 

    def __set_kernels(self):

        """Kernels used for image processing"""

        self.clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))

 

 

    def __set_perspective(self):

        """The src points draw a persepective trapezoid, the dst points draw

        them as a square.  M transforms x,y from trapezoid to square for

        a birds-eye view.  M_inv does the inverse.

        """

 

        src = np.float32([[(.42 * self.img_shape[1],.65 * self.img_shape[0] ),

                           (.58 * self.img_shape[1], .65 * self.img_shape[0]),

                           (0 * self.img_shape[1],self.img_shape[0]),

                           (1 * self.img_shape[1], self.img_shape[0])]])

 

        dst = np.float32([[0,0],

                          [self.img_shape[1],0],

                          [0,self.img_shape[0]],

                          [self.img_shape[1],self.img_shape[0]]])

 

        self.M = cv2.getPerspectiveTransform(src, dst)

        self.M_inv = cv2.getPerspectiveTransform(dst, src)

 

    def __set_mask_regions(self):

        """These are verticies used for clipping the image.

        """

        self.bottom_clip = np.int32(np.int32([[[60,0], [1179,0], [1179,650], [60,650]]]))

        self.roi_clip =  np.int32(np.int32([[[640, 425], [1179,550], [979,719],

                              [299,719], [100, 550], [640, 425]]]))

class LaneFinder(object):

    """

    The mighty LaneFinder takes in a video from the front camera of a self driving car

    and produces a new video with the traffic lanes highlighted and statistics about where

    the car is relative to the center of the lane shown.

    """    

 

    def __init__(self):

 

        self.g             = GlobalObjects()        

        self.thresholder   = tools.ImageThresholder()

        self.distCorrector = tools.DistortionCorrector(self.g.camera_cal_folder)

        self.histFitter    = tools.HistogramLineFitter()

        self.laneDrawer    = tools.LaneDrawer()

        self.leftLane      = tools.Line()

        self.rightLane     = tools.Line()

 

        return

 

    def __image_pipeline(self, img):

        """The pipeline for processing images. Globals g are added to functions that need

        access to global variables.

        """

        resized     = self.__resize_image(img)

        undistorted = self.__correct_distortion(resized)

        warped      = self.__warp_image_to_biv(undistorted)

        thresholded = self.__threshold_image(warped)

        lines       = self.__get_lane_lines(thresholded)

        result      = self.__draw_lane_lines(undistorted, thresholded, include_stats=False)

 

        return result

 

 

    def __draw_lane_lines(self, undistorted, thresholded, include_stats):

 

        lines = {'left_line': self.leftLane,

                 'right_line': self.rightLane }

 

        return self.laneDrawer.draw_lanes(undistorted,

                                          thresholded,

                                          lines,

                                          self.g.M_inv,

                                          include_stats)

 

    def __get_lane_lines(self, img):

 

        self.leftLane    = self.histFitter.get_line(img, self.leftLane, 'left')

        self.rightLane   = self.histFitter.get_line(img, self.rightLane, 'right')

 

        return True

 

    def __mask_region(self, img, vertices):

        """

        Masks a region specified by clockwise vertices.

        """

 

        mask = np.zeros_like(img)   

        if len(img.shape) > 2:

            channel_count = img.shape[2]  # i.e. 3 or 4 depending on your image

            ignore_mask_color = (255,) * channel_count

        else:

            ignore_mask_color = 255

        cv2.fillConvexPoly(mask, vertices, ignore_mask_color)

        masked_image = cv2.bitwise_and(img, mask)

        return masked_image

 

    def __resize_image(self, img):

        """

        Image is resized to the selected size for the project.

        """

        return cv2.resize(img, self.g.img_size,

                          interpolation = cv2.INTER_CUBIC)

 

    def __correct_distortion(self, img):

        return self.distCorrector.undistort(img)

 

    def __threshold_image(self, img):

        return self.thresholder.get_thresholded_image(img)

 

    def __warp_image_to_biv(self, img):

        return cv2.warpPerspective(img, self.g.M, self.g.img_size)

 

 

    def test_one_image(self, pt):

        image = (mpimg.imread(pt))

        return self.__image_pipeline(image)

11. 最终效果:

%matplotlib inline

obj = LaneFinder()

result = obj.test_one_image('./output/visualize_test6.jpg')print(type(result), result.shape)

 

plt.figure(figsize=(15,12))

plt.imshow(result)

plt.savefig('result.png')

plt.show()

Loading saved calibration file...

(720, 1280, 3)

 

关于作者:
北京理工大学 大二在读

感兴趣的方向为:目标检测、人脸识别、EEG识别等

将会定期分享一些小项目,感兴趣的朋友可以互相关注一下:主页链接

也欢迎大家fork、评论交流

作者博客地址:https://blog.csdn.net/weixin_44936889

 

0
收藏
回复
全部评论(12)
时间顺序
学习委员
#2 回复于2020-05

赞一个~

0
回复
半岛铁盒
#3 回复于2020-08

学习了

0
回复
Mr.郑先生_
#4 回复于2020-08

赞!

0
回复
七年期限
#5 回复于2020-08

666

0
回复
七年期限
#6 回复于2020-08

大赞

0
回复
半岛铁盒
#7 回复于2020-08

paddlex真的很适合小白

0
回复
aaaaaa
#8 回复于2020-09

0
回复
Mr.郑先生_
#9 回复于2020-09
paddlex真的很适合小白

但是真的很吃电脑配置

0
回复
七年期限
#10 回复于2020-09
但是真的很吃电脑配置

还有硬盘

0
回复
不败小段哥
#11 回复于2020-09

paddlex是真的好用,但是感觉支持的模型有点少,另外没有找到直接加载模型权重文件不进行训练直接预测的方法

0
回复
七年期限
#12 回复于2020-09
paddlex是真的好用,但是感觉支持的模型有点少,另外没有找到直接加载模型权重文件不进行训练直接预测的方法

我感觉图像化的超级方便 不用写代码 哈哈

0
回复
李长安
#13 回复于2021-12

优秀

0
回复
需求/bug反馈?一键提issue告诉我们
发现bug?如果您知道修复办法,欢迎提pr直接参与建设飞桨~
在@后输入用户全名并按空格结束,可艾特全站任一用户