欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

百度Apollo感知模块(perception)红绿灯检测代码解析

程序员文章站 2022-07-12 12:17:34
...

背景

最近在读apollo感知模块下的红绿灯检测,apollo框架思路清晰,风格规范,值得多读。直接上代码文件:trafficlights_perception_component.cc

trafficlights_perception_component.cc

整个trafficlights_perception_component.cc文件的函数主要分为三部分:以init开头的初始化部分,红绿灯模块的主函数OnReceiveImage,以及被主函数直接/间接调用的其他函数。
突然想写个记录,主函数已经扒得七七八八了,现在主要在抠细节,所以直接上细节函数的分析了,随写随更,部分简单的判断函数就不写了,懂的都懂。
ps:下面的函数顺序是按照函数的执行顺序写的,属于该文件的函数写在标题,不属于该文件的被调用的其他文件的函数挂在标题函数下面
pps: 目前自己c++技能还不太到位,有些描述不精准的自己看代码

UpdateLightsProjection()

  • 接收参数
const CarPose &pose;                                                              // 保存汽车相关信息的变量
const TLPreprocessorOption &option;                            // 这个没看懂是干什么的
const std::string &camera_name;                                      // 传来的相机名称,因为自动驾驶包括了多个摄像头,所以必须区分不同相机
std::vector<base::TrafficLightPtr> *lights;                     // 传来红绿灯信息指针,是个向量,向量每个元素就是一个红绿灯信息

清除变量,AINFO输出信息到日志:

lights_on_image_.clear();
lights_outside_image_.clear();
AINFO << "clear lights_outside_image_ " << lights_outside_image_.size();

判断lights指针是否为空。空则不需要做映射,因为红绿灯的检测是阶段性地启动,在汽车进入红绿检测范围才会执行红绿灯检测;非空则说明已经通过汽车的坐标获取到了红绿灯在三维世界的坐标。判断代码很简单,如下:

  if (lights->empty()) {
    AINFO << "No lights to be projected";
    return true;
  }

lights非空后执行映射函数ProjectLights(),该函数返回布尔值,以判断映射是否成功执行,映射失败则AERROR到监控器和日志中:

  if (!ProjectLights(pose, camera_name, lights, &lights_on_image_,  &lights_outside_image_)) {
    AERROR << "update_lights_projection project lights on " << camera_name  << " image failed";
    return false;
  }

判断映射后的图像坐标是否超出视频图像帧的范围:

  if (lights_outside_image_.size() > 0) {
    AERROR << "update_lights_projection failed," << "lights_outside_image->size() " << lights_outside_image_.size() << " ts: " << pose.getTimestamp();
    return false;
  }

后面的代码还没看,暂时不写了:

auto min_focal_len_working_camera = GetMinFocalLenWorkingCameraName();
  if (camera_name == min_focal_len_working_camera) {
    return lights_on_image_.size() > 0;
  }
  for (const base::TrafficLightPtr &light : lights_on_image_) {
    if (OutOfValidRegion(light->region.projection_roi,
                         projection_.getImageWidth(camera_name),
                         projection_.getImageHeight(camera_name),
                         option.image_borders_size->at(camera_name))) {
      AINFO << "update_lights_projection light project out of image region. "
            << "camera_name: " << camera_name;
      return false;
    }
  }

  AINFO << "UpdateLightsProjection success";
  return true;

ProjectLights()

  • 接收参数
const CarPose &pose;                                                              // 保存汽车相关信息的变量
const std::string &camera_name;                                      // 传来的相机名称,因为自动驾驶包括了多个摄像头,所以必须区分不同相机
std::vector<base::TrafficLightPtr> *lights;                     // 传来红绿灯信息指针,是个向量,向量每个元素就是一个红绿灯信息
base::TrafficLightPtrs *lights_on_image;                      // 指向一个向量的指针,向量的每个元素都是一个红绿灯指针,每个红绿灯指针指向一个红绿灯信息
base::TrafficLightPtrs *lights_outside_image;            // 同上 ,只是上面保存的是映射在图片中的红绿灯信息,这个保存了映射在图片外的红绿灯信息

读到第一部分发现和上个函数同样的指针判空,太好了可以抄自己作业:

判断lights指针是否为空。空则不需要做映射,因为红绿灯的检测是阶段性地启动,在汽车进入红绿检测范围才会执行红绿灯检测;非空则说明已经通过汽车的坐标获取到了红绿灯在三维世界的坐标。判断代码很简单,如下:

  if (lights->empty()) {
    AINFO << "No lights to be projected";
    return true;
  }

判断相机是否正确,相应模块是否启动。HasCamera判断相机相机名是否在相机名列表中,且相应的模块是否启动,返回布尔值:

  if (!projection_.HasCamera(camera_name)) {
    AERROR << "project_lights get invalid camera_name: " << camera_name;
    return false;
  }

相机没问题继续执行下面代码。初始化布尔变量is_working,调用**GetCameraWorkingFlag()**函数执行。注意,调用该函数时,传进的参数is_working是使用了引用&,也就意味着该函数执行会改变is_working的值,然后根据返回的布尔结果判断是否AWARN到日志中:

  // camera is not working
  bool is_working = false;
  if (!GetCameraWorkingFlag(camera_name, &is_working) || !is_working) {
    AWARN << "TLPreprocessor::project_lights not project lights, " << "camera is not working, camera_name: " << camera_name;
    return true;
  }

is_working在上面的代码执行后会从false变为true,表示相机正常工作,继续执行下面的代码:

for (size_t i = 0; i < lights->size(); ++i) {
    base::TrafficLightPtr light_proj(new base::TrafficLight);                                        // 申请一个新的TrafficLightPtr指针
    auto light = lights->at(i);                                                                                                      
    if (!projection_.Project(pose, ProjectOption(camera_name), light.get())) {  // 利用if判断被调函数Project结果,正常流程应该走else,进if则说明映射到帧上的坐标超出了图像大小
      light->region.outside_image = true;
      *light_proj = *light;
      lights_outside_image->push_back(light_proj);
    } else {
      light->region.outside_image = false;                   // 如果Project成功执行,则将light指针下的region下的outside_image设为false,表示没有超出图片
      *light_proj = *light;                                                      // 传递正确映射的指针
      lights_on_image->push_back(light_proj);        // 将指针推入lights_on_image向量中保存
    }
  }
  return true;                                                                          // 返回ProjectLights函数执行的结果,即正确执行

MultiCamerasProjection::Project()

  • 接收参数
const Eigen::Vector3f& point3d;                             //