【Apollo解读代码系列之perception】camera模块tracker逻辑分析

camera模块之tracker

  在apollo-camera模块的tracker中主要包含两个子文件夹:commonomt。其中common文件夹下面主要是状态估计【kalman_filter】与相似特征【similar】文件。

common中状态估计【kalman_filter】文件包含多种滤波器类对视觉感知目标进行滤波,下面的类导图有画出。主要包含均值滤波、卡尔曼滤波、低通滤波等等。

common下的相似特征【similar】文件主要对图像块直接求取相似度,有cpu与cuda加速两个计算方式。

omt文件夹下面主要包含【omt_obstacle_tracker】、【obstacle_reference】、【target】三个文件。另外【track_object】文件只是简单声明追踪的存储数据结构。

omt下的【omt_obstacle_tracker】主要应用类或者成为接口类,包含Predict()Associate2D()Assoctate3D()等公有函数。从该类可以看出视觉障碍物追踪在数据关联阶段不仅仅使用2D信息同时也使用3D目标信息进行关联。

omt文件夹下的【target】是具体对目标状态估计与更新函数。上面的【omt_obstacle_tracker】的函数内部具体实现都会调用具体【target】内部的函数。例如:【omt_obstacle_tracker】下面的predict()会调用【target】的predict()函数。

omt文件下的【obstacle_reference】主要是通过结合相机参数与估计地面,随后通过obstacle_template来对目标进行一定程度的修正。

apollo相机模块的tracker单元测试【提前编译好可执行文件】用例:

// path : /apollo/modules/perception/camera/test
./camera_lib_obstacle_tracker_omt_omt_obstacle_tracker_test
camera模块之主要结构图

相机tracker的类导图:

具体tracker之间的代码流程走图:

  上面基本上对camera的tracker有个简要介绍,可以得到基本了解。下面我们对【omt_obstacle_tracker】稍微有些细化介绍一下。

关于GenerateHypothesis函数是关联模块Associate2D()中核心函数之一,相关解释在注释中进行批注。

void OMTObstacleTracker::GenerateHypothesis(const TrackObjectPtrs &objects) {
  std::vector<Hypothesis> score_list;
  Hypothesis hypo;
  for (size_t i = 0; i < targets_.size(); ++i) {
    ADEBUG << "Target " << targets_[i].id;
    for (size_t j = 0; j < objects.size(); ++j) {
      hypo.target = static_cast<int>(i);
      hypo.object = static_cast<int>(j);
      // 计算targets_ 与 objects_ 之间的similar_map_相似度
      float sa = ScoreAppearance(targets_[i], objects[j]);
      // targets_与objects_之间的高斯motion分布值
      float sm = ScoreMotion(targets_[i], objects[j]);
      // shape之间的差距
      float ss = ScoreShape(targets_[i], objects[j]);
      // IoU
      float so = ScoreOverlap(targets_[i], objects[j]);
      // 加权获取hypo的value
      if (sa == 0) {
        hypo.score = omt_param_.weight_diff_camera().motion() * sm +
                     omt_param_.weight_diff_camera().shape() * ss +
                     omt_param_.weight_diff_camera().overlap() * so;
      } else {
        hypo.score = (omt_param_.weight_same_camera().appearance() * sa +
                      omt_param_.weight_same_camera().motion() * sm +
                      omt_param_.weight_same_camera().shape() * ss +
                      omt_param_.weight_same_camera().overlap() * so);
      }
      int change_from_type = static_cast<int>(targets_[i].type);
      int change_to_type = static_cast<int>(objects[j]->object->sub_type);
      // 这里存在类型转换矩阵,apollo里面有个先验矩阵值
      hypo.score += -kTypeAssociatedCost_[change_from_type][change_to_type];
      ADEBUG << "Detection " << objects[j]->indicator.frame_id << "(" << j
             << ") sa:" << sa << " sm: " << sm << " ss: " << ss << " so: " << so
             << " score: " << hypo.score;

      // 95.44% area is range [mu - sigma*2, mu + sigma*2]
      // don't match if motion is beyond the range
      if (sm < 0.045 || hypo.score < omt_param_.target_thresh()) {
        continue;
      }
      score_list.push_back(hypo);
    }
  }
  // 排序存储满足条件的score_list
  sort(score_list.begin(), score_list.end(), std::greater<Hypothesis>());
  std::vector<bool> used_target(targets_.size(), false);
  for (auto &pair : score_list) {
    if (used_target[pair.target] || used_[pair.object]) {
      continue;
    }
    Target &target = targets_[pair.target];
    auto det_obj = objects[pair.object];
    // 添加到target列表中
    target.Add(det_obj);
    used_[pair.object] = true;
    used_target[pair.target] = true;
    AINFO << "Target " << target.id << " match " << det_obj->indicator.frame_id
          << " (" << pair.object << ")"
          << "at " << pair.score << " size: " << target.Size();
  }
}

  上述GenerateHypothesis中加权求取时候用到kTypeAssociatedCost_来索引类别转换的概率值,这部分主要在【omt_obstacle_tracker】初始化里面type_change_cost的变量获取如下的矩阵。你会发现对角线都为0主要类别没有进行变化,有些类别转换权重为1.0有些为0.2分别表示类型变化错误的概率。这部分从侧面说明目标检测中类型检出模糊性或者变化的可能性。例如:当前是追踪列表目标为车,关联时候为人的概率,这种变化很大,所以应该给大权重值。反之如果追踪列表目标为轿车,关联时候为SUV的概率,这种变化相对较小,所以可以给予较小的权重值。

0.0 0.0 0.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0
0.0 0.0 0.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0
0.0 0.0 0.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0
1.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.2 1.0 1.0
1.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.2 1.0 1.0
1.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.2 1.0 1.0
1.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.2 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 0.0 0.2 0.1 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 0.0 0.2 0.1 1.0
1.0 1.0 1.0 0.2 0.2 0.2 0.2 0.2 0.2 0.0 0.2 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.1 0.1 0.2 0.0 1.0
0.0 0.0 0.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0

【omt_obstacle_tracker】关联模块Associate2D()

  基本上Associate2D函数主要是对图像平面的目标进行关联,首先计算两帧图像直接的相似度。同时也使用相机坐标系下面的3D投影至图像平面框进行计算。关于计算方式主要参考GenerateHypothesis生成对应的阈值。随后,使用CombineDuplicateTargets()函数通过IoU进行重复剔除。这里面有个重点就是:每次在target更新时候,有两个类型需要进行更新UpdateType()Update2D()是指类型与2D信息。

【omt_obstacle_tracker】关联模块Associate3D()这部分主要对target部分的3D目标信息进行更新。阅读target文件下面的Update3D()函数,主要是对world_center相关变量进行更新,对应状态估计是KalmanFilterConstVelocity

【omt_obstacle_tracker】预测部分Predict()内部调用targetpredict()函数。我们来看下targetpredict()函数:

void Target::Predict(CameraFrame *frame) {
  auto delta_t =
      static_cast<float>(frame->timestamp - latest_object->timestamp);
  if (delta_t < 0) {
    return;
  }
  image_center.Predict(delta_t); // image_center的predict
  float acc_variance = target_param_.world_center().process_variance();
  float delta_t_2 = delta_t * delta_t;
  float pos_variance = 0.25f * acc_variance * delta_t_2 * delta_t_2;
  float vel_variance = acc_variance * delta_t_2;
  world_center.process_noise_(0, 0) = pos_variance;
  world_center.process_noise_(1, 1) = pos_variance;
  world_center.process_noise_(2, 2) = vel_variance;
  world_center.process_noise_(3, 3) = vel_variance;
  world_center.Predict(delta_t); // world_center 的predict

  // const position kalman predict
  world_center_const.process_noise_.setIdentity();
  world_center_const.process_noise_(0, 0) = vel_variance * delta_t_2;
  world_center_const.process_noise_(1, 1) =
      world_center_const.process_noise_(0, 0);
  world_center_const.Predict(delta_t); // world_center_const 的predict
}

  上述代码可以清晰的看出,在target下的predict()函数,内部分别有3种预测方式。它们分别对应不同的状态估计方式,可以看target文件下的声明。同时,针对world_center相关信息变量,也分为运动or静止状态下的估计。

  阅读到这里,可能你会疑惑?一个kalmanfilter不就可以搞定所有的相机状态变量了,为什么还需要如此多的滤波方式来监测更新呢?这个就是apollo相机模式下追踪的细节工程体现,其实你想想在图像平面下目标物体的wh与中心点center变化规律。然后世界坐标系下whlworld_center的变化规律是否都变化率近似。答案是否定的,可以想象一下世界坐标系下物体center变化较whl变化更急剧一些,是否运动也会产生不同影响。所以,就有了KalmanFilterConstStateMaxNMeanFilter等。

小结

  阅读完apollo相机模块下面的追踪代码,给我一个感觉就是细致。它把视觉感知下的目标物体变量拆分出来,根据各自的特性使用不同的状态估计来进行监测与更新。同时,还对相机的每帧成像进行监测与目标物体纠正等。仔细阅读target文件下面的策略,基本上就是相机模块下的tracker流程与技术细节。ok,希望你看过这篇对你阅读代码能够更清楚的梳理了一遍。

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: Apollo Planning是一个自动驾驶规划模块,它负责生成自动驾驶车辆的行驶路线和行驶轨迹。该模块代码主要包括以下几个部分: 1. 地图数据处理:该部分代码主要负责处理地图数据,包括地图的加载、解析和存储等。 2. 车辆状态估计:该部分代码主要负责估计车辆的状态,包括车辆的位置、速度、加速度等。 3. 障碍物检测:该部分代码主要负责检测车辆周围的障碍物,包括车辆前方的障碍物、车辆后方的障碍物等。 4. 路径规划:该部分代码主要负责生成车辆的行驶路线,包括起点、终点、途经点等。 5. 轨迹规划:该部分代码主要负责生成车辆的行驶轨迹,包括车辆的速度、加速度、转向角度等。 总的来说,Apollo Planning的代码解读需要对自动驾驶技术有一定的了解,需要熟悉相关的算法和数据结构。同时,还需要对C++编程语言有一定的掌握,能够理解和修改代码。 ### 回答2: Apollo Planning是Apollo平台中的一部分,是一种规划算法,用于生成具有速度、加速度、路径跟踪、动态碰撞检测等约束条件的行驶路径。本文将对Apollo Planning中的代码进行解读Apollo Planning的核心代码包括两个部分:路径规划器和速度规划器。其中路径规划器的主要任务是在路网中寻找一条从起点到终点的路径,而速度规划器的主要任务则是为规划出的路径生成相应的速度规划和轨迹。 路径规划器中采用的主要算法是基于A*算法的全局规划器和基于Dijkstra算法的局部规划器。全局规划器用于从起点到终点寻找全局路径,而局部规划器则用于在全局路径的基础上进行优化,以生成最终的路径。 在速度规划器中,采用了二次规划、线性插值和基于速度和加速度约束的时间分配等算法,用于根据路网上提供的速度信息和预计的路况等因素生成规划速度和轨迹。 除此之外,还应用了动态碰撞检测算法,用于在行驶过程中实时检测障碍物,并调整行驶路径以避免碰撞。 总之,Apollo Planning的代码实现了较为完善的路径规划和速度规划功能,并且综合应用了多种算法和约束条件,使得车辆行驶更加安全、稳定。 ### 回答3: Apollo Planning 代码是百度自动驾驶平台 Apollo 中用于路径规划的组件。通过对代码解读,我们可以了解到路径规划背后的一系列算法和原理。 首先,Apollo Planning 首先需要载入地图信息,以确定行驶的区域和道路网络。这些地图信息包括道路形状、道路宽度、车道数量、速度限制和限制规则等。 然后,Apollo Planning 根据车辆当前位置和目的地位置,通过 A*算法或 Dijkstra 算法等规划出车辆行驶的路径。这一过程中,Apollo Planning 需要考虑各种限制条件,如道路的长度、转弯半径、速度限制、停止标志和交通信号灯等。 接下来,Apollo Planning 将规划出的路径转换为轨迹,以让车辆根据轨迹规划进行动作。这一过程需要考虑车辆的动力学特性,比如加速度、最大速度限制和最大转弯速度等。 在最终生成的行驶轨迹中,需要包含一些基础信息,如轨迹的时间戳、各个点的速度和加速度信息等。这些信息有助于车辆在运行过程中准确地遵守路径规划,并在行驶中做出适时的调整。 总之,Apollo Planning 的核心功能是确定车辆行驶的路线、行驶轨迹和行驶速度等。该组件通过高效的算法和细致的条件考虑,实现自动驾驶车辆的稳定、安全和高效的路径规划。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值