深度学习车道线检测之 LaneNet (使用tensorflow2.4.0跑通)

本文用来整理回顾所学知识,也能使视觉领域初学者的同伴们少走些弯路。

参考链接:无人驾驶汽车系统入门(三十)——基于深度神经网络LaneNet的车道线检测及ROS实现_AdamShan的博客-CSDN博客

论文原文地址:Towards End-to-End Lane Detection: an Instance Segmentation Approach

Tensorflow代码地址:lanenet-lane-detection

 现在作者维护的版本更新到了2021.4.29。我上传到了百度网盘里:

链接:https://pan.baidu.com/s/1XydBVV-niTo9GybRDhquww 
提取码:yos4 

 文件夹结构为:

```
lanenet-lane-detection-master
├─ .idea
│  └─ vcs.xml
├─ config
│  └─ tusimple_lanenet.yaml
├─ data
│  ├─ source_image
│  │  ├─ accuracy.png
│  │  ├─ binary_seg_loss.png
│  │  ├─ instance_seg_loss.png
│  │  ├─ lanenet_batch_test.gif
│  │  ├─ lanenet_binary_seg.png
│  │  ├─ lanenet_embedding.png
│  │  ├─ lanenet_instance_seg.png
│  │  ├─ lanenet_mask_result.png
│  │  ├─ network_architecture.png
│  │  ├─ qr.jpg
│  │  └─ total_loss.png
│  ├─ training_data_example
│  │  ├─ gt_binary_image
│  │  │  ├─ 0000.png
│  │  │  ├─ 0001.png
│  │  │  ├─ 0002.png
│  │  │  ├─ 0003.png
│  │  │  ├─ 0004.png
│  │  │  └─ 0005.png
│  │  ├─ gt_instance_image
│  │  │  ├─ 0000.png
│  │  │  ├─ 0001.png
│  │  │  ├─ 0002.png
│  │  │  ├─ 0003.png
│  │  │  ├─ 0004.png
│  │  │  └─ 0005.png
│  │  ├─ image
│  │  │  ├─ 0000.png
│  │  │  ├─ 0001.png
│  │  │  ├─ 0002.png
│  │  │  ├─ 0003.png
│  │  │  ├─ 0004.png
│  │  │  └─ 0005.png
│  │  ├─ train.txt
│  │  └─ val.txt
│  ├─ tusimple_ipm_remap.yml
│  └─ tusimple_test_image
│     ├─ 0.jpg
│     ├─ 1.jpg
│     ├─ 2.jpg
│     └─ 3.jpg
├─ data_provider
│  ├─ lanenet_data_feed_pipline.py
│  └─ tf_io_pipline_tools.py
├─ lanenet_model
│  ├─ lanenet.py
│  ├─ lanenet_back_end.py
│  ├─ lanenet_discriminative_loss.py
│  ├─ lanenet_front_end.py
│  ├─ lanenet_postprocess.py
│  └─ __init__.py
├─ LICENSE
├─ local_utils
│  ├─ config_utils
│  │  ├─ parse_config_utils.py
│  │  └─ __init__.py
│  └─ log_util
│     ├─ init_logger.py
│     └─ __init__.py
├─ mnn_project
│  ├─ config.ini
│  ├─ config_parser.cpp
│  ├─ config_parser.h
│  ├─ convert_lanenet_model_into_mnn_model.sh
│  ├─ dbscan.hpp
│  ├─ freeze_lanenet_model.py
│  ├─ kdtree.cpp
│  ├─ kdtree.h
│  ├─ lanenet_model.cpp
│  ├─ lanenet_model.h
│  └─ __init__.py
├─ README.md
├─ requirements.txt
├─ semantic_segmentation_zoo
│  ├─ bisenet_v2.py
│  ├─ cnn_basenet.py
│  ├─ vgg16_based_fcn.py
│  └─ __init__.py
├─ tools
│  ├─ evaluate_lanenet_on_tusimple.py
│  ├─ evaluate_model_utils.py
│  ├─ generate_tusimple_dataset.py
│  ├─ make_tusimple_tfrecords.py
│  ├─ test_lanenet.py
│  └─ train_lanenet_tusimple.py
├─ trainner
│  ├─ tusimple_lanenet_multi_gpu_trainner.py
│  ├─ tusimple_lanenet_single_gpu_trainner.py
│  └─ __init__.py
└─ _config.yml

```

一、使用TensorFlow2.4.0实现及基于tuSimple数据集的模型训练

1. tuSimple数据集准备

下载地址:tusimple数据集

我也将它上传到了百度网盘:

链接:https://pan.baidu.com/s/1ZyH4_tV7Nxphrb4MBt7Lcw 
提取码:9ioq 

下载完成后解压缩到一个目录下,目录内容如下:

tuSimple/
├── clips
│   ├── 0313-1
│   ├── 0313-2
│   ├── 0530
│   ├── 0531
│   └── 0601
├── label_data_0313.json
├── label_data_0531.json
├── label_data_0601.json
├── readme.md
└── test_tasks_0627.json

将解压好的tuSimple文件夹放置于data目录下。

2. 如何将代码在 TensorFlow 2.4.0上使用

只需在每个需要导入 TensorFlow 模块的.py文档中加入下述语句:

import tensorflow
tensorflow.compat.v1.disable_eager_execution()
tf = tensorflow.compat.v1

这样就可以在TensorFlow 2.4.0运行 TensorFlow 1.0 版本的代码。

使用以下命令安装一下运行代码所需的包。注意这里的requirements.txt文件中的包可能版本比较老,如果和TensorFlow 2.4.0不兼容,升级一下即可。

pip install -r requirements.txt

3. 生成用于训练的数据

使用项目lanenet-lane-detection中的脚本generate_tusimple_dataset.py产生用于训练的binary mask和instance mask;

3.1 生成文件夹training和testing

根据.json文件转换训练集,生成图片文件夹gt_image、gt_binary_image、gt_instance_image 以及文本文件 train.txt。

在终端输入以下命令:

cd ./tools
python generate_tusimple_dataset.py --src_dir=D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple

此处需要等待几分钟:

在tuSimple目录下自动生成了trainingtesting两个目录,如下所示:

tuSimple/
|
├──training/
|   ├── gt_binary_image
|   ├── gt_image
|   ├── gt_instance_image
|   ├── label_data_0313.json
|   ├── label_data_0531.json
|   ├── label_data_0601.json
|   └── train.txt
└──testing/
    └── test_tasks_0627.json

 可见该脚本仅生成了train.txt,我们可以手动分割一下train set和val set,也就是剪切train.txt中的一部分到一个新建的val.txt和test.txt文件中。

打开train.txt,可以看到共有3626行数据,此处我粘贴了400行到val.txt中,200行粘贴到test.txt中。这里可以在合理范围内自己设置。

之后运行代码可能遇到的问题:

ModuleNotFoundError: No module named 'data_provider'  

只需在代码前加上以下语句:

import sys
import os
sys.path.append(os.getcwd())

3.2 将标注格式转换成TFRecord

3.2.1 更改config目录下的tusimple_lanenet.yaml文件。

更改数据集的路径,如下所示。

DATASET:
    DATA_DIR: 'D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple\training'
    IMAGE_TYPE: 'rgb'  # choice rgb or rgba
    NUM_CLASSES: 2
    TEST_FILE_LIST: 'D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple\training\test.txt'
    TRAIN_FILE_LIST: 'D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple\training\train.txt'
    VAL_FILE_LIST: 'D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple\training\val.txt'
    IGNORE_INDEX: 255
    PADDING_VALUE: [127.5, 127.5, 127.5]
    MEAN_VALUE: [0.5, 0.5, 0.5]
    STD_VALUE: [0.5, 0.5, 0.5]
    CPU_MULTI_PROCESS_NUMS: 8

3.2.2 使用脚本生成tfrecord文件

命令如下:

cd ..
python tools/make_tusimple_tfrecords.py --dataset_dir D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple\training --tfrecords_dir D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple\training\tfrecords

等待几分钟,脚本会在项目的data/training/tfrecords目录下生成相应的tfrecord文件,如下所示:

4. 训练自己的数据集

4.1更改代码:

 更改data_provider\lanenet_data_feed_pipline.py第799行

def get_next(self,name=None):
    return self._next_internal()
# def get_next(self):
#    return self._next_internal()

4.2 开始训练

运行 tools/train_lanenet_tusimple.py,开始训练:

也可以在终端中输入:

python tools/train_lanenet.py --dataset_dir D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\data\tuSimple\training --multi_gpus False

使用tensorboard查看训练过程

cd tboard/tusimple/bisenetv2_lanenet
tensorboard --logdir=.

在训练过程中,可以通过tensorboard查看模型在验证集上的总损失(val_cost)、分割损失(val_binary_seg_loss)、嵌入损失(val_instance_seg_loss)以及分割精度(val_accuracy)变化曲线,如下所示:

在这里插入图片描述

 还可以查看模型在训练过程中的分割分支和嵌入分支输出到预测图,如下图所示:

在这里插入图片描述

若出现以下问题:

2021-11-15 21:43:06.595835: I tensorflow/stream_executor/cuda/cuda_driver.cc:789] failed to allocate 2.20G (2363280384 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory

更改config目录下的tusimple_lanenet.yaml文件中的 batch_num (从32改为8)

TRAIN:
    MODEL_SAVE_DIR: 'model/tusimple/'
    TBOARD_SAVE_DIR: 'tboard/tusimple/'
    MODEL_PARAMS_CONFIG_FILE_NAME: "model_train_config.json"
    RESTORE_FROM_SNAPSHOT:
        ENABLE: False
        SNAPSHOT_PATH: ''
    SNAPSHOT_EPOCH: 8
    BATCH_SIZE: 8
    VAL_BATCH_SIZE: 4
    EPOCH_NUMS: 905
    WARM_UP:
        ENABLE: True
        EPOCH_NUMS: 8
    FREEZE_BN:
        ENABLE: False
    COMPUTE_MIOU:
        ENABLE: True
        EPOCH: 1
    MULTI_GPU:
        ENABLE: True
        GPU_DEVICES: ['0', '1']
        CHIEF_DEVICE_INDEX: 0
SOLVER:
    LR: 0.001
    LR_POLICY: 'poly'
    LR_POLYNOMIAL_POWER: 0.9
    OPTIMIZER: 'sgd'
    MOMENTUM: 0.9
    WEIGHT_DECAY: 0.0005
    MOVING_AVE_DECAY: 0.9995
    LOSS_TYPE: 'cross_entropy'
    OHEM:
        ENABLE: False
        SCORE_THRESH: 0.65
        MIN_SAMPLE_NUMS: 65536
GPU:
    GPU_MEMORY_FRACTION: 0.9
    TF_ALLOW_GROWTH: True
POSTPROCESS:
    MIN_AREA_THRESHOLD: 100
    DBSCAN_EPS: 0.35
    DBSCAN_MIN_SAMPLES: 1000
LOG:
    SAVE_DIR: './log'
    LEVEL: INFO

这里我们仍然是训练的tuSimple数据集,也可以制作自己的数据集。

训练好的权重 百度网盘链接:

链接:https://pan.baidu.com/s/1iNvf6IfU9Fg718xIhze4rg 
提取码:9b0a 
复制这段内容后打开百度网盘手机App,操作更方便哦

将权重文件放在model目录下,然后就可以测试结果了。

5. 测试结果

 终端输入:

python tools/test_lanenet.py --weights_path D:\DOCS\deepl_lane_detection\lanenet-lane-detection-master\model\tusimple_lanenet.ckpt --image_path ./data/tusimple_test_image/0.jpg

结果: 

二、代码及原理知识梳理(未完待续)

整体架构总览图

上图为LaneNet车道线检测的网络结构。这是一种端到端的车道线检测算法,包括LaneNet和H-Net两个网络模型。

其中,LaneNet是一种将语义分割和对像素进行向量表示结合起来的多任务模型,目的是将不同车道线实例化(通过用车道 id 标记每个车道像素来输出车道实例图);

H-Net是由卷积层和全连接层组成的网络模型,负责预测转换矩阵H,目的是对属于同一车道线的像素点进行回归(该矩阵学习以输入图像为条件的透视变换)。

对于每条车道,拟合三阶多项式并将车道重新投影到图像上。下文将具体介绍每一部分实现的功能。

1. LaneNet网络架构

LaneNet网络架构

如图,有两个解码分支:

1)Segmentation branch 负责对输入图像进行语义分割(对像素进行二分类,判断像素属于车道线还是背景),得到Binary image;

为了训练一个这样的分割网络,原论文使用了tuSimple数据集,在数据集中,车道线可能被其他车辆阻挡,在这种情况下,将车道线的标注(Ground truth)贯穿障碍物,如下图所示,从而使得分割网络在车道线被其他障碍物阻挡的情况下,依然可以完整检测出完整的车道线像素。

分割网络使用标准的交叉熵损失函数进行训练,对于这个逐像素分类任务而言(车道线像素/非车道线像素分类),由于两个类别的像素极度不均衡,为了处理此问题,作者使用了bounded inverse class weighting方法。

实例分割任务由两部分组成,分割和聚类部分,在下面的部分中更详细地解释。 为了在速度和准确性方面提高性能 [27],这两个部分在多任务网络中联合训练

2) Embedding branch 对像素进行嵌入式表示,论文将嵌入式向量的维度设置为4,训练得到的 embedding 向量用于聚类。最后将两个分支的结果进行结合利用 Mean-Shift 算法进行聚类,得到实例分割的结果。

不受可以检测的车道数量的限制,并且能够应对车道变化。

通过叠加嵌入分支和分割分支,在使用神经网络提取出车道线像素的同时,还能够对每个车道线实现聚类(即像素属于哪一根车道线)。为了训练这样的聚类嵌入网络,聚类损失函数(嵌入网络)包含两部分,方差项 L v a r L_{var}Lvar​ 和距离项 L d i s t L_{dist}Ldist​ ,其中 L v a r L_{var}Lvar​ 将每个嵌入的向量往某条车道线聚类中心(均值)方向拉,这种“拉力”激活的前提是嵌入向量到平均嵌入向量的距离过远,大于阈值 δ v \delta_vδv​ ; L d i s t L_{dist}Ldist​ 使两个类别的车道线越远越好,激活这个“推力”的前提是两条车道线聚类中心的距离过近,近于阈值 δ d \delta_dδd​ 。最后总的损失函数L的公式如下:

在这里插入图片描述

其中 C CC 表示聚类的数量(也就是车道线的数量),N c N_cNc​ 表示聚类 c cc 中的元素数量,x i x_ixi​ 表示一个像素嵌入向量, μ c \mu_{c}μc​ 表示聚类 c cc 的均值向量,[ x ] + = m a x ( 0 , x ) [x]_{+} = max(0, x)[x]+​=max(0,x),最后的损失函数为 L = L v a r + L d i s t L = L_{var} + L_{dist}L=Lvar​+Ldist​ 。该损失函数在实际实现(TensorFlow)中代码如下:

2. H-Net网络架构

1. generate_tusimple_dataset.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 18-5-18 下午7:31
# @Author  : MaybeShewill-CV
# @Site    : https://github.com/MaybeShewill-CV/lanenet-lane-detection
# @File    : generate_tusimple_dataset.py
# @IDE: PyCharm Community Edition
"""
generate tusimple training dataset
"""
import argparse
import glob
import json
import os
import os.path as ops
import shutil
import sys
sys.path.append(os.getcwd())

import cv2
import numpy as np


def init_args():
    """

    :return:
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('--src_dir', type=str, help='The origin path of unzipped tusimple dataset')

    return parser.parse_args()


def process_json_file(json_file_path, src_dir, ori_dst_dir, binary_dst_dir, instance_dst_dir):
    """

    :param json_file_path:
    :param src_dir: origin clip file path
    :param ori_dst_dir:
    :param binary_dst_dir:
    :param instance_dst_dir:
    :return:
    """
    assert ops.exists(json_file_path), '{:s} not exist'.format(json_file_path)

    image_nums = len(os.listdir(ori_dst_dir))

    with open(json_file_path, 'r') as file:
        for line_index, line in enumerate(file):
            info_dict = json.loads(line)

            image_dir = ops.split(info_dict['raw_file'])[0]
            image_dir_split = image_dir.split('/')[1:]
            image_dir_split.append(ops.split(info_dict['raw_file'])[1])
            image_name = '_'.join(image_dir_split)
            image_path = ops.join(src_dir, info_dict['raw_file'])
            assert ops.exists(image_path), '{:s} not exist'.format(image_path)

            h_samples = info_dict['h_samples']
            lanes = info_dict['lanes']

            image_name_new = '{:s}.png'.format('{:d}'.format(line_index + image_nums).zfill(4))

            src_image = cv2.imread(image_path, cv2.IMREAD_COLOR)
            dst_binary_image = np.zeros([src_image.shape[0], src_image.shape[1]], np.uint8)
            dst_instance_image = np.zeros([src_image.shape[0], src_image.shape[1]], np.uint8)

            for lane_index, lane in enumerate(lanes):
                assert len(h_samples) == len(lane)
                lane_x = []
                lane_y = []
                for index in range(len(lane)):
                    if lane[index] == -2:
                        continue
                    else:
                        ptx = lane[index]
                        pty = h_samples[index]
                        lane_x.append(ptx)
                        lane_y.append(pty)
                if not lane_x:
                    continue
                lane_pts = np.vstack((lane_x, lane_y)).transpose()
                lane_pts = np.array([lane_pts], np.int64)

                cv2.polylines(dst_binary_image, lane_pts, isClosed=False,
                              color=255, thickness=5)
                cv2.polylines(dst_instance_image, lane_pts, isClosed=False,
                              color=lane_index * 50 + 20, thickness=5)

            dst_binary_image_path = ops.join(binary_dst_dir, image_name_new)
            dst_instance_image_path = ops.join(instance_dst_dir, image_name_new)
            dst_rgb_image_path = ops.join(ori_dst_dir, image_name_new)

            cv2.imwrite(dst_binary_image_path, dst_binary_image)
            cv2.imwrite(dst_instance_image_path, dst_instance_image)
            cv2.imwrite(dst_rgb_image_path, src_image)

            print('Process {:s} success'.format(image_name))


def gen_train_sample(src_dir, b_gt_image_dir, i_gt_image_dir, image_dir):
    """
    generate sample index file
    :param src_dir:
    :param b_gt_image_dir:
    :param i_gt_image_dir:
    :param image_dir:
    :return:
    """

    with open('{:s}/training/train.txt'.format(src_dir), 'w') as file:

        for image_name in os.listdir(b_gt_image_dir):
            if not image_name.endswith('.png'):
                continue

            binary_gt_image_path = ops.join(b_gt_image_dir, image_name)
            instance_gt_image_path = ops.join(i_gt_image_dir, image_name)
            image_path = ops.join(image_dir, image_name)

            assert ops.exists(image_path), '{:s} not exist'.format(image_path)
            assert ops.exists(instance_gt_image_path), '{:s} not exist'.format(instance_gt_image_path)

            b_gt_image = cv2.imread(binary_gt_image_path, cv2.IMREAD_COLOR)
            i_gt_image = cv2.imread(instance_gt_image_path, cv2.IMREAD_COLOR)
            image = cv2.imread(image_path, cv2.IMREAD_COLOR)

            if b_gt_image is None or image is None or i_gt_image is None:
                print('图像对: {:s}损坏'.format(image_name))
                continue
            else:
                info = '{:s} {:s} {:s}'.format(image_path, binary_gt_image_path, instance_gt_image_path)
                file.write(info + '\n')
    return


def process_tusimple_dataset(src_dir):
    """

    :param src_dir:
    :return:
    """
    traing_folder_path = ops.join(src_dir, 'training')
    testing_folder_path = ops.join(src_dir, 'testing')

    os.makedirs(traing_folder_path, exist_ok=True)
    os.makedirs(testing_folder_path, exist_ok=True)

    for json_label_path in glob.glob('{:s}/label*.json'.format(src_dir)):
        json_label_name = ops.split(json_label_path)[1]

        shutil.copyfile(json_label_path, ops.join(traing_folder_path, json_label_name))

    for json_label_path in glob.glob('{:s}/test*.json'.format(src_dir)):
        json_label_name = ops.split(json_label_path)[1]

        shutil.copyfile(json_label_path, ops.join(testing_folder_path, json_label_name))

    gt_image_dir = ops.join(traing_folder_path, 'gt_image')
    gt_binary_dir = ops.join(traing_folder_path, 'gt_binary_image')
    gt_instance_dir = ops.join(traing_folder_path, 'gt_instance_image')

    os.makedirs(gt_image_dir, exist_ok=True)
    os.makedirs(gt_binary_dir, exist_ok=True)
    os.makedirs(gt_instance_dir, exist_ok=True)

    for json_label_path in glob.glob('{:s}/*.json'.format(traing_folder_path)):
        process_json_file(json_label_path, src_dir, gt_image_dir, gt_binary_dir, gt_instance_dir)

    gen_train_sample(src_dir, gt_binary_dir, gt_instance_dir, gt_image_dir)

    return


if __name__ == '__main__':
    args = init_args()

    process_tusimple_dataset(args.src_dir)

2. 

三、一些参考文献

1、图森TuSimple车道线检测数据集介绍_十栋前的猫的博客-CSDN博客

 tusimple-benchmark/doc/lane_detection at master · TuSimple/tusimple-benchmark · GitHub

简略总结:

tuSimple数据集大约包括7000个1秒钟长的20帧的视频剪辑(clips)。只有每个剪辑的最后一帧的车道带标签。

数据集的规模:

  1. 训练:3626个视频剪辑,3626个带标注的帧(每个剪辑clips有20帧,最后一帧带有标注)
  2. 测试:2782个视频剪辑

数据集采集时复杂条件:1. 复杂的天气条件(良好和中等) 2. 白天傍晚 3. 车道线数量(2/3/4/甚至更多) 4. 复杂的路况

注释类型: 折现标记

2、[深度学习] 车道线检测调研(lane detection)_Holeung blog-CSDN博客

 深度学习车道线检测论文集

<think>好的,用户的问题是关于如何在ROS2中实现车道线检测与避障功能的。首先,我需要理解用户的需求。他们可能正在开发一个自动驾驶或机器人项目,需要结合视觉检测和运动控制来实现这两个功能。根据提供的引用内容,特斯拉的视觉系统可以检测可驾驶区域和车道线,而ROS中的Twist消息用于控制机器人的线速度和角速度。用户可能希望将这两者结合起来,在ROS2环境下实现。 接下来,我需要分解问题。车道线检测常涉及图像处理或深度学习模型,而避障可能需要传感器数据如激光雷达或摄像头,以及相应的算法如SLAM或路径规划。ROS2的架构使用节点和话题,因此需要设计相应的节点来处理图像数据、执行检测算法,并发布控制指令。 然后,考虑如何将特斯拉的视觉检测方法应用到ROS2中。可能需要使用OpenCV或深度学习框架如TensorFlow/PyTorch来处理摄像头数据,检测车道线。同时,避障可能需要集成激光雷达的数据,使用如move_base或Navigation2包来处理路径规划和避障。 还需要考虑如何将检测结果转化为控制指令,比如使用Twist消息来调整机器人的线速度和角速度,确保它保持在车道内并避开障碍物。可能需要编写一个控制节点,订阅车道线检测和避障的结果,然后发布Twist命令到机器人的驱动节点。 用户可能还需要具体的步骤,比如如何设置ROS2包,依赖哪些库,如何编写发布者和订阅者,以及如何测试整个系统。此外,可能需要推荐现有的教程或工具,比如使用Gazebo进行仿真,或者使用现有的数据集来训练车道线检测模型。 最后,要确保回答结构清晰,分步骤说明,并引用提供的资料中的相关信息,比如特斯拉的视觉检测和ROS中的Twist消息应用,同时提供代码示例和注意事项,帮助用户实际实施时避免常见问题。</think>以下是在ROS2中实现车道线检测与避障功能的详细步骤: ### 一、车道线检测实现 1. **摄像头数据获取** ```python # 创建图像订阅节点 import rclpy from sensor_msgs.msg import Image from cv_bridge import CvBridge class CameraSubscriber(Node): def __init__(self): super().__init__('camera_subscriber') self.subscription = self.create_subscription( Image, '/camera/image_raw', self.image_callback, 10) self.bridge = CvBridge() def image_callback(self, msg): cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") # 后续处理... ``` 2. **图像处理流程**: - 使用OpenCV进行颜色空间转换(BGR→HSV) - 应用Canny边缘检测算法 - 基于霍夫变换的线段检测 - 使用滑动窗口法拟合车道线 3. **深度学习检测**(以PyTorch为例): ```python import torch from torchvision import transforms model = torch.load('lane_detection_model.pth') transform = transforms.Compose([ transforms.Resize((256, 512)), transforms.ToTensor() ]) def detect_lanes(image): input_tensor = transform(image).unsqueeze(0) output = model(input_tensor) # 后处理输出... ``` ### 二、避障功能实现 1. **传感器数据融合** ```python # 激光雷达订阅节点 from sensor_msgs.msg import LaserScan class LidarSubscriber(Node): def __init__(self): super().__init__('lidar_subscriber') self.subscription = self.create_subscription( LaserScan, '/scan', self.scan_callback, 10) def scan_callback(self, msg): # 处理360度扫描数据 obstacles = self.process_scan(msg.ranges) ``` 2. **避障算法选择**: - 动态窗口法(DWA) - 人工势场法 - 基于强化学习的避障 3. **运动控制集成**: ```python # 控制指令发布节点 from geometry_msgs.msg import Twist class Controller(Node): def __init__(self): super().__init__('motion_controller') self.publisher = self.create_publisher(Twist, '/cmd_vel', 10) def publish_command(self, linear, angular): msg = Twist() msg.linear.x = linear msg.angular.z = angular self.publisher.publish(msg) ``` ### 三、系统集成架构 ``` ROS2节点图: 摄像头节点 → 图像处理节点 → 车道检测结果 激光雷达节点 → 避障处理节点 → 安全区域信息 ↓ 决策节点 → 控制指令 → 底盘驱动节点 ``` ### 四、测试与调试 1. 使用Gazebo仿真环境搭建测试场景 2. 使用RViz可视化检测结果 3. 性能优化建议: - 使用FPGA加速图像处理 - 多线程处理传感器数据 - 采用时间同步机制
评论 43
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值