vision_ssd_detect 代码解读
在Autoware平台的Core Perception模块中实现了如何利用SSD模型进行图片目标检测的示例,下面将对该部分的代码及所需的环境配置进行详细介绍和解读。首先进入src/autoware/core_perception/vision_ssd_detect/launch/vision_ssd_detect.launch
文件,可以看到这部分主要包含vision_ssd_detect和visualize_rects两个节点,如下图2所示:
这里还需注意的是在argument list中定义了网络配置文件(network_definition_file)和预训练模型文件(pretrained_model_file)地址,可以根据实际需要进行自定义。
SSD Caffe环境配置
在开始代码解读前,首先需要配置SSD Caffe环境。Caffe[3]是一个开源的深度学习框架,专注于计算机视觉的应用研究。配置SSD Caffe环境主要包括以下几个步骤:
(1) 进入Caffe官网,进行ubuntu系统的Caffe预编译过程。值得注意的是,ubuntu系统对Caffe框架支持较好,对CPU和GPU两个版本的Caffe都有很好的兼容性。
(2) 将SSD Caffe项目克隆到本地,并根据项目要求进行预编译。
% git clone -b ssd https://github.com/weiliu89/caffe.git ssdcaffe
% cd ssdcaffe
% git checkout 4817bf8b4200b35ada8ed0dc378dceaf38c539e4
(3) 编译Caffe
make && make distribute
(4) (可选) 从SSD Caffe项目中下载预训练模型(https://github.com/weiliu89/caffe/tree/ssd),或也可以选择自己训练好的模型。
(5) 一旦编译完成,在终端(terminal)中运行
roslaunch vision_ssd_detect vision_ssd_detect network_definition_file:=/PATH/TO/deploy.prototxt pretrained_model_file:=/PATH/TO/model.caffemodel
特别注意的是,需要将这里network_definition_file
和pretrained_model_file
与src/autoware/core_perception/vision_ssd_detect/launch/vision_ssd_detect.launch
中相应的地址保持一致。这样,就可以完成SSD Caffe的环境配置,以便在Autoware Core Perception模块中使用。
vision_ssd_detect节点
在src/autoware/core_perception/vision_ssd_detect/src/vison_ssd_detect_node.cpp
中定义了SSD检测算法的主要操作细节。首先,找到main()函数入口,其中对SSD算法参数进行初始化,调用类方法ROSSSDApp(),并执行run(),如下图3所示:
类方法ROSSSDApp()
在类方法中,声明了ROS接收节点 命名空间节点以及opencv中图像像素参数. 同时定义了 置信阈值,GPU设备号,是否使用GPU,目标类别的命名空间参数
convert_to_detected_object()方法
该函数对检测结果进行信息转换用来组装out_message发布检测结果 将in_object转移到obj中,在push_back到out_message
image_callback()方法
回调函数中定义了输入图片的预处理操作,其功能包括
- 转换图片格式 toCvCopy
- 调用SSD算法进行目标检测 ssd_detector_->Detect
- 发布结果 publisher_detected_objects_.publish
Run()方法
利用构造函数的信息 INFO到terminal,定义字符变量/接收输入/网络配置文件和预训练模型文件等.
最后将定义好的内容,在SSDDetector类方法中进行模型初始化
利用advertise和subscriber实现发布和接收 advertise方法能够回调一个publisher对象 并通过publish发布信息.
visualize_rects节点
在src/autoware/core_perception/visualization/detected_objects_visualizer/src/visualize_rects_main.cpp
是visualize_rects节点的主函数入口。如下图10所示,main()主函数下同样包含参数初始化、调用类方法VisualizeRects以及spin()节点等操作。
类方法VisualizeRects()
在src/autoware/core_perception/visualization/detected_objects_visualizer/include/visualize_rects.h
下定义类方法VisualizeRects。除了常规地声明ROS命名空间和信息收发节点、标准变量等操作外,这里进一步定义SyncedDetectionCallback()方法、IsObjectValid()方法以及ObjectsToRects()方法。
SyncedDetectionCallback()方法
在src/autoware/core_perception/visualization/detected_objects_visualizer/src/visualize_rects.cpp
中对SyncedDetectionCall()方法进行具体化。,该方法主要是利用ObjectToRects()方法,在图片上画出目标的区域并将检测的结果(目标坐标位置、类别信息等)发布。
ObjectToRects()方法
同样,在src/autoware/core_perception/visualization/detected_objects_visualizer/src/visualize_rects.cpp
中对ObjectToRects()方法进行具体化。首先对图片进行复制,以便后续绘制目标矩形框。接着利用IsObjectValid()方法判断目标的有效性,并进行一以下操作:确定矩形框的中心坐标、宽度、高度、目标类别标签等信息,并设置所要添加的文字字体、尺寸等参数。最后,在先前复制的图片上绘制目标矩形框,并添加必要的信息。
IsObjectValid()方法
在src/autoware/core_perception/visualization/detected_objects_visualizer/src/visualize_rects.cpp
中通过IsObjectValid()方法简单判断目标是否有效,即通过目标尺寸的正负形来确定。
trafficlight_recognizer
首先进入src/autoware/core_perception/trafficlight_recognizer/launch
,在该文件夹下共包含feat_proj.launch、roi_extractor.launch、traffic_llight_recognition_mxnet.launch、traffic_light_recognition_ssd.launch、traffic_light_recognition.launch
等五个文件。
feat_proj
feat_proj部分的主要功能是通过一些投影变换获取信号灯的位置信息.
在src/autoware/core_perception/trafficlight_recognizer/launch中,feat_proj.launch
文件主要包含一些基础参数信息,如camera_id、use_path_info等,以及节点feat_proj信息.
节点feat_proj
在src/autoware/core_perception/trafficlight_recognizer/nodes/feat_proj/feat_proj.cpp
文件中找到主函数main(),其中包含参数初始化、加载vector_map()方法(load_point()、load_lines()、load_vectors()方法等)、并调用cameraInfoCallback()、adjust_xyCallback()、getTransform()、echSignals2()等方法来获取信号灯的位置,
vector_map()方法
在src/autoware/common/libvectormap/src/vector_map.cpp
中定义了相关方法的具体操作,以load_points()方法为例。如下图3所示,该方法主要是用于加载point并进行一些必要的操作,以获取点坐标信息及位置关系。
cameraInfoCallback()方法
在src/autoware/core_perception/trafficlight_recognizer/nodes/feat_proj/feat_proj.cpp
文件中定义了cameraInfoCallback()方法的具体操作,其主要用于获取相机参数信息及图片相关参数.
adjust_xyCallback()方法
同样在src/autoware/core_perception/trafficlight_recognizer/nodes/feat_proj/feat_proj.cpp
文件中定义了adjust_xyCallback()方法的具体操作.
getTransform()方法
getTransform()方法主要是用于进行图片变换,以便获取位置和方向参数
echoSignals2()方法
在src/autoware/core_perception/trafficlight_recognizer/nodes/feat_proj/feat_proj.cpp
文件中还定义了echoSignals2()方法,通过一系列的投影变换获取信号灯不同角度的位置信息,如下图7所示。首先,建立服务器(server)与信号灯之间的相应关系,以获取信号灯数据;随后,调用project2()方法对位置坐标进行变换,得到相应的投影坐标;最后,利用GetSignalAngleInCameraSystem()方法计算相机坐标系下信号灯角度信息。
project2()方法
project2()方法的返回结果是一个布尔值,该方法主要是用于获取世界坐标点在图像平面的投影变换结果,随后进一步判断点坐标与图像平面的位置关系
GetSignalAngleInCameraSystem()方法
该方法的返回结果是一个双精度值,用于获取相机坐标系统下信号灯的角度信息。
首选通过ConvertDegreeToRadian()方法将vector_map进行弧度变换,获取ROS格式下的几何信息(roll、pitch、yaw等);然后,通过相机坐标系统分别对信号灯的几何信息进行转换;最后再调用ConvertRadianToDegree()方法获取信号灯角度信息。
ConvertDegreeToRadian()方法和ConvertRadianToDegree()方法
ConvertDegreeToRadian()和ConvertRadianToDegree()两种方法的返回结果均为双精度值,主要功能是实现角度-弧度、弧度-角度的变换过程.
roi_extractor
roi_extractor部分主要是用于获取信号灯的roi区域,在src/autoware/core_perception/trafficlight_recognizer/launch中,roi_extractor.launch文件包含一些基础参数信息,如target_directory、minimum_height、similarity_threshold等,以及节点roi_extractor信息
节点roi_extractor
在src/autoware/core_perception/trafficlight_recognizer/nodes/roi_extractor/roi_extractor.cpp
文件中找到主函数main(),首先对节点参数进行初始化并获取必要的参数信息(image_topic_name、target_directory_name等);随后分别调用CreateTargetDirectory()、ImageRawCallback()、ROISignalCallback()方法接收并存储信号灯roi区域图片
CreateTargetDirectory()方法
在src/autoware/core_perception/trafficlight_recognizer/nodes/roi_extractor/roi_extractor.cpp
中定义了CreateTargetDirectory()方法的具体操作,如下图13所示,该方法通过调用MakeDirectoryTree()方法创建目录并调用CountFileNum()方法统计目录下的文件数量,最后根据所确定的目录名和文件名存储信号灯roi图片
MakeDirectoryTree()方法
MakeDirectoryTree()方法的功能是用于创建目录结构
CountFileNum()方法
CountFileNum()方法的返回结果是一个整型值,用于统计目标目录下所包含的文件数.
ImageRawCallback()方法
ImageRawCallback()方法用于对图片进行处理,并保留系统时间戳数据以确保相同图片不会被重复处理
ROISignalCallback()方法
ROISignalCallback()方法用于获取信号灯roi区域的位置信息。该方法首先确定图片中顶部信号灯的初步位置,并提取其roi区域;随后调用CalculateSimilarity()方法计算图片的相似度,以进一步获取确定的roi信息。最后保存相应的信号的roi图片并记录时间戳信息。
CalculateSimilarity()方法
CalculateSimilarity()方法返回一个双精度结果,主要是通过对比两张图片的直方图差异性来间接计算图片的相似度。首先,创建对图片进行颜色空间变换并量化hue值;然后,分别计算两张图片的直方图差异性得到相似度水平。
traffic_light_recognition_mxnet() 方法
traffic_light_recognition_mxnet部分主要是通过深度学习框架mxnet[1],调用目标识别模型来解决交通信号灯识别问题。值得注意的是,在开始该部分学习之前需要安装mxnet框架并配置相关的运行环境。进入src/autoware/core_perception/trafficlight_recognizer/launch,在traffic_light_recognition_mxnet.launch文件中包含了参数列表以及节点region_tlr_mxnet信息
节点region_tlr_mxnet
在src/autoware/core_perception/trafficlight_recognizer/nodes/region_tlr_mxnet/region_tlr_mxnet.cpp
文件中找到main()函数,其中包括初始化ROS节点参数,并调用类方法RegionTLRMxNetROSNode()的RunRecognition()方法进行信号灯识别等操作.
RunRecognition()方法
RunRecognition()方法主要定义了信号灯的识别过程 首先调用GetROSParam()方法从ROS服务端获取参数信息;然后,调用Init()方法初始化目标识别模型参数;最后通过StartSubscribersAndPublishers()方法开启ROS节点,用于接收和发布信息
GetROSParam()方法
GetROSParam()方法主要用于获取ROS节点参数信息,包括图片名(image_topic_name)、网络配置文件(network_definition_file)、预训练模型文件(pretrained_model_file)等
Init()方法
src/autoware/core_perception/trafficlight_recognizer/nodes/region_tlr_mxnet/mxnet_traffic_light_recognizer.cpp,文件中定义了Init()方法的具体操作,该方法的主要功能是初始化网络参数并进行信号灯识别。首先定义一些必要参数,包括是否使用gpu、gpu id、前向传播过程(num_input_nodes),并对输入尺寸的格式进行限制等;然后利用mxnet框架创建预测层(MXPredCreate),导入预训练模型文件和网络配置文件进行信号灯识别。
StartSubscribersAndPublishers()方法
在src/autoware/core_perception/trafficlight_recognizer/nodes/region_tlr_mxnet/mxnet_traffic_light_recognizer.cpp
文件中,StartSubscribersAndPublishers()方法用于启动ROS信息接收节点。首先,启动信息接收节点,并调用ImageRawCallback()、ROISignalCallback()和SuperimposeCb()方法接收输入图片、信号灯ROI区域并对其进行处理;然后,通过信息发布节点,将信号灯状态(颜色)、信号灯位置识别结果等信息发布。
ImageRawCallback()方法
ImageRawCallback()方法主要用于对图片进行创建、复制等初步处理.
ROISignalCallback()方法
ROISignalCallback()方法主要用于对信号灯ROI区域进行处理,从而获取信号灯状态信息。首先在图中对应信号灯ROI区域,以确定信号灯位置;然后,调用RecognizeLightState()、DetermineState()方法识别并更新信号灯状态;最后通过PublishTrafficLight()、PublishString()、PublishMarkerArray()、PublishImage()方法将识别结果发布,并保存时间戳信息。
RecognizeLightState()方法
在src/autoware/core_perception/trafficlight_recognizer/nodes/region_tlr_mxnet/mxnet_traffic_light_recognizer.cpp
文件中,RecognizeLightState()方法用于识别信号灯的状态。该方法接收信号灯图片并调用PreProccessImage()方法对图片进行预处理;然后调用mxnet框架中预测层方法进行信号灯识别,并根据识别结果将其转为对应的信号灯状态。
PreProcessImage()方法
PreProcessImage()方法主要用于对输入图片的尺寸、通道进行预处理,以适应网络输入的尺寸
traffic_light_recognition_ssd
traffic_light_recognition_ssd部分主要是通过利用SSD模型来识别交通信号灯
这里侧重介绍如何Autoware平台中调用SSD模型并识别交通信号灯。进入src/autoware/core_perception/trafficlight_recognizer/launch,在traffic_light_recognition_ssd.launch
文件中包含了参数列表以及节点region_tlr_ssd信息
节点region_tlr_ssd
在src/autoware/core_perception/trafficlight_recognizer/nodes/region_tlr_ssd/region_tlr_ssd.cpp
文件中找到main()函数入口,其中包括初始化ROS节点参数,并调用类方法RegionTLRSSDROSNode()的RunRecognition()方法进行信号灯识别等操作
RunRecognition()方法
RunRecognition()方法同样是用于识别信号灯
主要流程如下:
-
该方法首先调用GetROSParam()方法从ROS服务端获取参数信息;
-
调用Init()方法初始化SSD模型参数;
-
调用StartSubscribersAndPublishers()方法开启ROS信息收发节点:
信息接收节点:ImageRawCallback()和ROISignalCallback()方法接收信号灯图片并获取位置信息,ROISignalCallback()方法调用RecognizeLightState()、DetermineState()方法确定信号灯状态:RecognizeLightState()方法调用WrapInputLayer()、Preprocess()方法对图片进行处理;ROISignalCallback()方法调用PublishTrafficLight()、PublishString()、PublishMarkerArray()等方法以特定格式发布结果
信息发布节点:发布信号灯状态(颜色)、识别结果等信息。
traffic_light_recognition
traffic_light_recognition部分主要用于识别交通信号灯并对识别结果进行微调,在src/autoware/core_perception/trafficlight_recognizer/launch
中,traffic_light_recognition.launch文件主要包含节点region_lr、节点tl_switch及其相关参数信息
节点region_tlr
在src/autoware/core_perception/trafficlight_recognizer/nodes/region_tlr/region_tlr.cpp文件中定义了该部分所采用的具体方法。 在main()函数中首先定义了红、黄、绿三种颜色的HSV取值阈值,并初始化ROS节点参数;然后,调用image_raw_cb()、extractedPos_cb()、tunedResult_cb()和superimpose_cb()方法提取信号灯位置信息并对结果进行微调显示;最后,通过ROS节点将识别结果发布。
image_raw_cb()方法
对输入图片进行预处理,调用putResult_inText方法将识别结果添加到图片上
putResult_inText()方法
put_Result_inText()方法主要是将信号灯识别结果与状态标签对应起来,并在图片上添加状态标签、车道等信息.
Autoware平台开展交通信号灯识别项目,主要包括feat_proj、roi_extractor、region_tlr_mxnet、region_tlr_ssd、region_tlr和tl.switch五个节点内容,理清整个项目的流程并解析各个方法的具体操作。