精华内容
下载资源
问答
  • 利用多帧融合方法探测新闻视频标题字幕,郭金林,老松杨,新闻视频是一类重要的视频资源,新闻视频中的标题字幕是实现自动视频语义内容分析的重要线索。本文提出了一种新的探测新闻视频标
  • 行业分类-物理装置-基于多帧融合光流的视频超分辨率重建方法.zip
  • 基于颜色聚类和多帧融合的视频文字识别方法.pdf
  • 算法适用于多曝光融合代码,同时不同间存在着运动物体,比起传统的HDR,可以极大的避免由于运动物体的出现带来的鬼影效果,同时又很强的自适应去噪效果,很适合工程实现,
  • 针对这种情况,提出一种融合多特征的视频间篡改检测算法。该算法首先计算视频的空间信息和时间信息值并对视频进行分组,接着计算视频间连续性VQA特征,然后结合SVM–RFE特征递归消除算法对不同特征排序,最后...
  • 融合多模型和间信息的行人检测算法
  • 电信设备-基于多帧信息融合的米波阵列雷达目标仰角测量方法.zip
  • 提出一种图像的自嵌入水印算法,该算法将图像分块奇异值分解,并提取每块的最大奇异值实施量化生成量化图像。量化图像生成的二值编码经过置乱和混沌加密后嵌入到原始图像的置零位之中。算法不仅能检测和定位对图像的...
  • 【图像处理】多帧降噪算法

    万次阅读 2017-03-30 00:08:25
    多帧降噪算法 视频去噪算法

    本文参考论文:Denoising image sequences does not require motion estimation
    http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.131.6394&rep=rep1&type=pdf

    这篇论文主要写的是如何利用多帧图像进行降噪处理。

    论文主要从以下几个部分展开:
    1、NLmeans
    先是介绍了non local means降噪算法。该算法之前有介绍过,主要是通过单帧图像中的冗余信息来进行降噪处理。通过在一帧图像中查找当前像素的相似像素点,然后对这些像素进行加权平均操作。评判是否相似可以有多种方式,基于L2或者高斯核等等。

    2、把nlmeans引申到多帧场景。
    多帧场景中,在不同帧的类似像素点位置,总是能够找到类似的像素点,因此,通过这些像素点的加权平均,我们也可以得到较为干净的图像。
    作者表示这样的操作可以避免运动估计处理,运动估计不仅费时,而且如果存在误差,对于结果则会适得其反。而查找类似像素点的方式并不会严格要求图像对齐。

    3、多帧降噪与其他算法对比
    其他算法包括光流法、模版匹配法进行运动估计的算法。

    总的来说,这篇论文还是比较好理解的。关键在于如何压缩算法复杂度,怎样保证快速高效才是重点。该算法可以运用在video denoising的场景,但是如何达到实时,还需要不断的尝试。后续在这方面有进展再进行更新。

    展开全文
  • 传感器融合算法,雷视融合算法

    千次阅读 2021-01-23 19:07:10
    求跟踪器所有目标状态预测与本检测的box的IOU,通过匈牙利指派算法得到IOU最大的唯一匹配(数据关联部分),再去掉匹配值小于iou_threshold的匹配对。 用本中匹配到的目标检测box去更新卡尔曼跟踪器,计算卡尔曼...

    在这里插入图片描述

    0: 设备选型

    Camera选型: 如何选择视场角和焦距:

    在这里插入图片描述

    Radar选型

    在这里插入图片描述

    lidar选型

    在这里插入图片描述

    1: Radar毫米波雷达和Camera视觉融合

    算法要求:
    图像目标检测
    Radar目标检测
    radar和camera标定

    融合效果

    例如:
    在这里插入图片描述
    可用作交通事件分析

    2: Lidar激光雷达和Camera视觉融合

    算法要求:
    图像目标检测
    Lidar目标检测
    Lidar和camera标定

    效果展示:

    左边图像目标检测和融合效果
    右边Lidar目标检测

    基于图像深度学习目标检测
    基于激光雷达的深度学习目标检测

    融合目标,重新画框显示可视化,赋予车辆速度信息

    在这里插入图片描述
    在这里插入图片描述

    3: Lidar激光雷达和Radar毫米波雷达融合

    算法要求:
    图像目标检测
    Radar目标检测
    Radar和camera标定
    在这里插入图片描述

    融合的前提之跟踪算法

    4: camera跟踪算法

    匈牙利算法(又叫KM算法)就是用来解决分配问题的一种方法,它基于定理:

    如果代价矩阵的某一行或某一列同时加上或减去某个数,则这个新的代价矩阵的最优分配仍然是原代价矩阵的最优分配。
    算法步骤(假设矩阵为NxN方阵):

    1:对于矩阵的每一行,减去其中最小的元素
    2:对于矩阵的每一列,减去其中最小的元素
    3:用最少的水平线或垂直线覆盖矩阵中所有的0
    4:如果线的数量等于N,则找到了最优分配,算法结束,否则进入步骤
    5:找到没有被任何线覆盖的最小元素,每个没被线覆盖的行减去这个元素,每个被线覆盖的列加上这个元素,返回步骤3

    图像的跟踪算法的理解

    在跟踪之前,对所有目标已经完成检测,实现了特征建模过程。

    1. 第一帧进来时,以检测到的目标初始化并创建新的跟踪器,标注id。
    2. 后面帧进来时,先到卡尔曼滤波器中得到由前面帧box产生的状态预测和协方差预测。求跟踪器所有目标状态预测与本帧检测的box的IOU,通过匈牙利指派算法得到IOU最大的唯一匹配(数据关联部分),再去掉匹配值小于iou_threshold的匹配对。
      https://blog.csdn.net/u011837761/article/details/52058703
    3. 用本帧中匹配到的目标检测box去更新卡尔曼跟踪器,计算卡尔曼增益、状态更新和协方差更新,并将状态更新值输出,作为本帧的跟踪box。对于本帧中没有匹配到的目标重新初始化跟踪器。

    其中,卡尔曼跟踪器联合了历史跟踪记录,调节历史box与本帧box的残差,更好的匹配跟踪id。

    message WeightParam {
    optional float appearance = 1 [default = 0];
    optional float motion = 2 [default = 0];
    optional float shape = 3 [default = 0];
    optional float tracklet = 4 [default = 0];
    optional float overlap = 5 [default = 0];
    }
    message OmtParam {
    optional int32 img_capability = 1 [default = 7];
    optional int32 lost_age = 2 [default = 2];
    optional int32 reserve_age = 3 [default = 3];
    optional WeightParam weight_same_camera = 4;
    optional WeightParam weight_diff_camera = 5;
    optional float border = 9 [default = 30];
    optional float target_thresh = 10 [default = 0.65];
    optional bool correct_type = 11 [default = false];
    optional TargetParam target_param = 12;
    optional float min_init_height_ratio = 13 [default = 17];
    optional float target_combine_iou_threshold = 14 [default = 0.5];
    optional float fusion_target_thresh = 15 [default = 0.45];
    optional float image_displacement = 16 [default = 50];
    optional float abnormal_movement = 17 [default = 0.3];
    optional double same_ts_eps = 18 [default = 0.05];
    optional ReferenceParam reference = 19;
    optional string type_change_cost = 20;
    }

    如果采用算法,可以综合以下,计算关联矩阵
      float sa = ScoreAppearance(targets_[i], objects[j]);
      float sm = ScoreMotion(targets_[i], objects[j]);
      float ss = ScoreShape(targets_[i], objects[j]);
      float so = ScoreOverlap(targets_[i], objects[j]);
      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);
      }
    

    5: Lidar跟踪算法

    https://blog.csdn.net/lemonxiaoxiao/article/details/108645427

    perception/lidar/lib/tracker/multi_lidar_fusion/mlf_track_object_matcher.cc
    
    
    void MlfTrackObjectMatcher::Match(
        const MlfTrackObjectMatcherOptions &options,
        const std::vector<TrackedObjectPtr> &objects,
        const std::vector<MlfTrackDataPtr> &tracks,
        std::vector<std::pair<size_t, size_t>> *assignments,
        std::vector<size_t> *unassigned_tracks,
        std::vector<size_t> *unassigned_objects) {
      assignments->clear();
      unassigned_objects->clear();
      unassigned_tracks->clear();
      if (objects.empty() || tracks.empty()) {
        unassigned_objects->resize(objects.size());
        unassigned_tracks->resize(tracks.size());
        std::iota(unassigned_objects->begin(), unassigned_objects->end(), 0);
        std::iota(unassigned_tracks->begin(), unassigned_tracks->end(), 0);
        return;
      }
    
      BipartiteGraphMatcherOptions matcher_options;
      matcher_options.cost_thresh = max_match_distance_;
      matcher_options.bound_value = bound_value_;
    
      BaseBipartiteGraphMatcher *matcher =
          objects[0]->is_background ? background_matcher_ : foreground_matcher_;
    
      common::SecureMat<float> *association_mat = matcher->cost_matrix();
    
      association_mat->Resize(tracks.size(), objects.size());
      ComputeAssociateMatrix(tracks, objects, association_mat);
      matcher->Match(matcher_options, assignments, unassigned_tracks,
                     unassigned_objects);
      for (size_t i = 0; i < assignments->size(); ++i) {
        objects[assignments->at(i).second]->association_score =
            (*association_mat)(assignments->at(i).first,
                               assignments->at(i).second) /
            max_match_distance_;
      }
    }
    
    float MlfTrackObjectDistance::ComputeDistance(
        const TrackedObjectConstPtr& object,
        const MlfTrackDataConstPtr& track) const {
      bool is_background = object->is_background;
      const TrackedObjectConstPtr latest_object = track->GetLatestObject().second;
      std::string key = latest_object->sensor_info.name + object->sensor_info.name;
      const std::vector<float>* weights = nullptr;
      if (is_background) {
        auto iter = background_weight_table_.find(key);
        if (iter == background_weight_table_.end()) {
          weights = &kBackgroundDefaultWeight;
        } else {
          weights = &iter->second;
        }
      } else {
        auto iter = foreground_weight_table_.find(key);
        if (iter == foreground_weight_table_.end()) {
          weights = &kForegroundDefaultWeight;
        } else {
          weights = &iter->second;
        }
      }
      if (weights == nullptr || weights->size() < 7) {
        AERROR << "Invalid weights";
        return 1e+10f;
      }
      float distance = 0.f;
      float delta = 1e-10f;
    
      double current_time = object->object_ptr->latest_tracked_time;
      track->PredictState(current_time);
    
      double time_diff =
          track->age_ ? current_time - track->latest_visible_time_ : 0;
      if (weights->at(0) > delta) {
        distance +=
            weights->at(0) * LocationDistance(latest_object, track->predict_.state,
                                              object, time_diff);
      }
      if (weights->at(1) > delta) {
        distance +=
            weights->at(1) * DirectionDistance(latest_object, track->predict_.state,
                                               object, time_diff);
      }
      if (weights->at(2) > delta) {
        distance +=
            weights->at(2) * BboxSizeDistance(latest_object, track->predict_.state,
                                              object, time_diff);
      }
      if (weights->at(3) > delta) {
        distance +=
            weights->at(3) * PointNumDistance(latest_object, track->predict_.state,
                                              object, time_diff);
      }
      if (weights->at(4) > delta) {
        distance +=
            weights->at(4) * HistogramDistance(latest_object, track->predict_.state,
                                               object, time_diff);
      }
      if (weights->at(5) > delta) {
        distance += weights->at(5) * CentroidShiftDistance(latest_object,
                                                           track->predict_.state,
                                                           object, time_diff);
      }
      if (weights->at(6) > delta) {
        distance += weights->at(6) *
                    BboxIouDistance(latest_object, track->predict_.state, object,
                                    time_diff, background_object_match_threshold_);
      }
      // for foreground, calculate semantic map based distance
    //  if (!is_background) {
    //    distance += weights->at(7) * SemanticMapDistance(*track, object);
    //  }
    
      return distance;
    }
    
    /******************************************************************************
     * Copyright 2018 The Apollo Authors. All Rights Reserved.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     *****************************************************************************/
    #include <algorithm>
    #include <vector>
    
    #include "cyber/common/log.h"
    #include "modules/common/math/line_segment2d.h"
    #include "modules/common/math/vec2d.h"
    #include "modules/perception/common/geometry/basic.h"
    #include "modules/perception/common/geometry/common.h"
    #include "modules/perception/lidar/lib/tracker/association/distance_collection.h"
    
    float LocationDistance(const TrackedObjectConstPtr& last_object,
                           const Eigen::VectorXf& track_predict,
                           const TrackedObjectConstPtr& new_object,
                           const double time_diff) {
      // Compute locatin distance for last object and new object
      // range from 0 to positive infinity
    
      Eigen::Vector3f measured_anchor_point =
          (new_object->anchor_point).cast<float>();
      Eigen::Vector3f predicted_anchor_point = track_predict.head(3);
      Eigen::Vector3f measure_predict_diff =
          measured_anchor_point - predicted_anchor_point;
    
      float location_dist = static_cast<float>(sqrt(
          (measure_predict_diff.head(2).cwiseProduct(measure_predict_diff.head(2)))
              .sum()));
    
      /* NEED TO NOTICE: All the states would be collected mainly based on
       * states of tracked objects. Thus, update tracked object when you
       * update the state of track !!!!! */
      Eigen::Vector2d ref_dir = last_object->output_velocity.head(2);
      double speed = ref_dir.norm();
      ref_dir /= speed;
    
      /* Let location distance generated from a normal distribution with
       * symmetric variance. Modify its variance when speed greater than
       * a threshold. Penalize variance other than motion direction. */
      if (speed > 2) {
        Eigen::Vector2d ref_o_dir = Eigen::Vector2d(ref_dir[1], -ref_dir[0]);
        double dx = ref_dir(0) * measure_predict_diff(0) +
                    ref_dir(1) * measure_predict_diff(1);
        double dy = ref_o_dir(0) * measure_predict_diff(0) +
                    ref_o_dir(1) * measure_predict_diff(1);
        location_dist = static_cast<float>(sqrt(dx * dx * 0.5 + dy * dy * 2));
      }
    
      return location_dist;
    }
    
    float DirectionDistance(const TrackedObjectConstPtr& last_object,
                            const Eigen::VectorXf& track_predict,
                            const TrackedObjectConstPtr& new_object,
                            const double time_diff) {
      // Compute direction distance for last object and new object
      // range from 0 to 2
    
      Eigen::Vector3f old_anchor_point =
          (last_object->belief_anchor_point).cast<float>();
      Eigen::Vector3f new_anchor_point = (new_object->anchor_point).cast<float>();
      Eigen::Vector3f anchor_point_shift_dir = new_anchor_point - old_anchor_point;
      anchor_point_shift_dir[2] = 0.0;
    
      Eigen::Vector3f track_motion_dir = track_predict.head(6).tail(3);
      track_motion_dir[2] = 0.0;
    
      double cos_theta = 0.994;  // average cos
      if (!track_motion_dir.head(2).isZero() &&
          !anchor_point_shift_dir.head(2).isZero()) {
        // cos_theta = vector_cos_theta_2d_xy(track_motion_dir,
        //                                   anchor_point_shift_dir);
        cos_theta = common::CalculateCosTheta2DXY<float>(track_motion_dir,
                                                         anchor_point_shift_dir);
      }
      float direction_dist = static_cast<float>(-cos_theta) + 1.0f;
    
      return direction_dist;
    }
    
    float BboxSizeDistance(const TrackedObjectConstPtr& last_object,
                           const Eigen::VectorXf& track_predict,
                           const TrackedObjectConstPtr& new_object,
                           const double time_diff) {
      // Compute bbox size distance for last object and new object
      // range from 0 to 1
    
      Eigen::Vector3f old_bbox_dir = last_object->output_direction.cast<float>();
      Eigen::Vector3f new_bbox_dir = new_object->direction.cast<float>();
      Eigen::Vector3f old_bbox_size = last_object->output_size.cast<float>();
      Eigen::Vector3f new_bbox_size = new_object->size.cast<float>();
    
      float size_dist = 0.0f;
      double dot_val_00 = fabs(old_bbox_dir(0) * new_bbox_dir(0) +
                               old_bbox_dir(1) * new_bbox_dir(1));
      double dot_val_01 = fabs(old_bbox_dir(0) * new_bbox_dir(1) -
                               old_bbox_dir(1) * new_bbox_dir(0));
      float temp_val_0 = 0.0f;
      float temp_val_1 = 0.0f;
      if (dot_val_00 > dot_val_01) {
        temp_val_0 = static_cast<float>(fabs(old_bbox_size(0) - new_bbox_size(0))) /
                     std::max(old_bbox_size(0), new_bbox_size(0));
        temp_val_1 = static_cast<float>(fabs(old_bbox_size(1) - new_bbox_size(1))) /
                     std::max(old_bbox_size(1), new_bbox_size(1));
        size_dist = std::min(temp_val_0, temp_val_1);
      } else {
        temp_val_0 = static_cast<float>(fabs(old_bbox_size(0) - new_bbox_size(1))) /
                     std::max(old_bbox_size(0), new_bbox_size(1));
        temp_val_1 = static_cast<float>(fabs(old_bbox_size(1) - new_bbox_size(0))) /
                     std::max(old_bbox_size(1), new_bbox_size(0));
        size_dist = std::min(temp_val_0, temp_val_1);
      }
    
      return size_dist;
    }
    
    float PointNumDistance(const TrackedObjectConstPtr& last_object,
                           const Eigen::VectorXf& track_predict,
                           const TrackedObjectConstPtr& new_object,
                           const double time_diff) {
      // Compute point num distance for last object and new object
      // range from 0 and 1
    
      int old_point_number = static_cast<int>(
          (last_object->object_ptr->lidar_supplement).cloud_world.size());
      int new_point_number = static_cast<int>(
          (new_object->object_ptr->lidar_supplement).cloud_world.size());
    
      float point_num_dist =
          static_cast<float>(fabs(old_point_number - new_point_number)) * 1.0f /
          static_cast<float>(std::max(old_point_number, new_point_number));
    
      return point_num_dist;
    }
    
    float HistogramDistance(const TrackedObjectConstPtr& last_object,
                            const Eigen::VectorXf& track_predict,
                            const TrackedObjectConstPtr& new_object,
                            const double time_diff) {
      // Compute histogram distance for last object and new object
      // range from 0 to 3
    
      const std::vector<float>& old_object_shape_features =
          last_object->shape_features;
      const std::vector<float>& new_object_shape_features =
          new_object->shape_features;
    
      if (old_object_shape_features.size() != new_object_shape_features.size()) {
        AINFO << "sizes of compared features not matched. TrackObjectDistance";
        return 100;
      }
    
      float histogram_dist = 0.0f;
      for (size_t i = 0; i < old_object_shape_features.size(); ++i) {
        histogram_dist +=
            std::fabs(old_object_shape_features[i] - new_object_shape_features[i]);
      }
    
      return histogram_dist;
    }
    
    float CentroidShiftDistance(const TrackedObjectConstPtr& last_object,
                                const Eigen::VectorXf& track_predict,
                                const TrackedObjectConstPtr& new_object,
                                const double time_diff) {
      float dist = static_cast<float>(
          (last_object->barycenter.head(2) - new_object->barycenter.head(2))
              .norm());
      return dist;
    }
    
    float BboxIouDistance(const TrackedObjectConstPtr& last_object,
                          const Eigen::VectorXf& track_predict,
                          const TrackedObjectConstPtr& new_object,
                          const double time_diff, double match_threshold) {
      // Step 1: unify bbox direction, change the one with less pts,
      // for efficiency.
      Eigen::Vector3f old_dir = last_object->output_direction.cast<float>();
      Eigen::Vector3f old_size = last_object->output_size.cast<float>();
      Eigen::Vector3d old_center = last_object->output_center;
      Eigen::Vector3f new_dir = new_object->direction.cast<float>();
      Eigen::Vector3f new_size = new_object->size.cast<float>();
      Eigen::Vector3d new_center = new_object->center;
      old_dir.normalize();
      new_dir.normalize();
      // handle randomness
      old_size(0) = old_size(0) > 0.3f ? old_size(0) : 0.3f;
      old_size(1) = old_size(1) > 0.3f ? old_size(1) : 0.3f;
      new_size(0) = new_size(0) > 0.3f ? new_size(0) : 0.3f;
      new_size(1) = new_size(1) > 0.3f ? new_size(1) : 0.3f;
      int last_object_num_pts = static_cast<int>(
          (last_object->object_ptr->lidar_supplement).cloud_world.size());
      int cur_obj_num_pts = static_cast<int>(
          (new_object->object_ptr->lidar_supplement).cloud_world.size());
      bool change_cur_obj_bbox = last_object_num_pts > cur_obj_num_pts;
      float minimum_edge_length = 0.01f;
      base::PointDCloud& cloud =
          (new_object->object_ptr->lidar_supplement).cloud_world;
      if (change_cur_obj_bbox) {
        new_dir = old_dir;
        common::CalculateBBoxSizeCenter2DXY(cloud, new_dir, &new_size, &new_center,
                                            minimum_edge_length);
      } else {
        old_dir = new_dir;
        common::CalculateBBoxSizeCenter2DXY(cloud, old_dir, &old_size, &old_center,
                                            minimum_edge_length);
      }
      // Step 2: compute 2d iou bbox to bbox
      Eigen::Matrix2d trans_mat;
      trans_mat(0, 0) = (old_dir.cast<double>())(0);
      trans_mat(0, 1) = (old_dir.cast<double>())(1);
      trans_mat(1, 0) = -(old_dir.cast<double>())(1);
      trans_mat(1, 1) = (old_dir.cast<double>())(0);
      Eigen::Vector2d old_center_transformed_2d =
          static_cast<Eigen::Matrix<double, 2, 1, 0, 2, 1>>(trans_mat *
                                                            old_center.head(2));
      Eigen::Vector2d new_center_transformed_2d =
          static_cast<Eigen::Matrix<double, 2, 1, 0, 2, 1>>(trans_mat *
                                                            new_center.head(2));
      old_center(0) = old_center_transformed_2d(0);
      old_center(1) = old_center_transformed_2d(1);
      new_center(0) = new_center_transformed_2d(0);
      new_center(1) = new_center_transformed_2d(1);
      Eigen::Vector3d old_size_tmp = old_size.cast<double>();
      Eigen::Vector3d new_size_tmp = new_size.cast<double>();
      double iou = common::CalculateIou2DXY<double>(old_center, old_size_tmp,
                                                    new_center, new_size_tmp);
      // Step 4: compute dist
      double dist = (1 - iou) * match_threshold;
      return static_cast<float>(dist);
    }
    
    
    
    

    ‘’‘
    ’‘’

    6:Radar跟踪算法

    bool HMMatcher::Match(const std::vector<RadarTrackPtr> &radar_tracks,
                          const base::Frame &radar_frame,
                          const TrackObjectMatcherOptions &options,
                          std::vector<TrackObjectPair> *assignments,
                          std::vector<size_t> *unassigned_tracks,
                          std::vector<size_t> *unassigned_objects) {
      IDMatch(radar_tracks, radar_frame, assignments, unassigned_tracks,
              unassigned_objects);
      TrackObjectPropertyMatch(radar_tracks, radar_frame, assignments,
                               unassigned_tracks, unassigned_objects);
      return true;
    }
    
    bool HMMatcher::RefinedTrack(const base::ObjectPtr &track_object,
                                 double track_timestamp,
                                 const base::ObjectPtr &radar_object,
                                 double radar_timestamp) {
      double dist = 0.5 * DistanceBetweenObs(track_object, track_timestamp,
                                             radar_object, radar_timestamp) +
                    0.5 * DistanceBetweenObs(radar_object, radar_timestamp,
                                             track_object, track_timestamp);
    
      return dist < BaseMatcher::GetMaxMatchDistance();
    }
    
    void HMMatcher::TrackObjectPropertyMatch(
        const std::vector<RadarTrackPtr> &radar_tracks,
        const base::Frame &radar_frame, std::vector<TrackObjectPair> *assignments,
        std::vector<size_t> *unassigned_tracks,
        std::vector<size_t> *unassigned_objects) {
      if (unassigned_tracks->empty() || unassigned_objects->empty()) {
        return;
      }
      std::vector<std::vector<double>> association_mat(unassigned_tracks->size());
      for (size_t i = 0; i < association_mat.size(); ++i) {
        association_mat[i].resize(unassigned_objects->size(), 0);
      }
      ComputeAssociationMat(radar_tracks, radar_frame, *unassigned_tracks,
                            *unassigned_objects, &association_mat);
    
      // from perception-common
      common::SecureMat<double> *global_costs =
          hungarian_matcher_.mutable_global_costs();
      global_costs->Resize(unassigned_tracks->size(), unassigned_objects->size());
      for (size_t i = 0; i < unassigned_tracks->size(); ++i) {
        for (size_t j = 0; j < unassigned_objects->size(); ++j) {
          (*global_costs)(i, j) = association_mat[i][j];
        }
      }
      std::vector<TrackObjectPair> property_assignments;
      std::vector<size_t> property_unassigned_tracks;
      std::vector<size_t> property_unassigned_objects;
      hungarian_matcher_.Match(
          BaseMatcher::GetMaxMatchDistance(), BaseMatcher::GetBoundMatchDistance(),
          common::GatedHungarianMatcher<double>::OptimizeFlag::OPTMIN,
          &property_assignments, &property_unassigned_tracks,
          &property_unassigned_objects);
    
      for (size_t i = 0; i < property_assignments.size(); ++i) {
        size_t gt_idx = unassigned_tracks->at(property_assignments[i].first);
        size_t go_idx = unassigned_objects->at(property_assignments[i].second);
        assignments->push_back(std::pair<size_t, size_t>(gt_idx, go_idx));
      }
      std::vector<size_t> temp_unassigned_tracks;
      std::vector<size_t> temp_unassigned_objects;
      for (size_t i = 0; i < property_unassigned_tracks.size(); ++i) {
        size_t gt_idx = unassigned_tracks->at(property_unassigned_tracks[i]);
        temp_unassigned_tracks.push_back(gt_idx);
      }
      for (size_t i = 0; i < property_unassigned_objects.size(); ++i) {
        size_t go_idx = unassigned_objects->at(property_unassigned_objects[i]);
        temp_unassigned_objects.push_back(go_idx);
      }
      *unassigned_tracks = temp_unassigned_tracks;
      *unassigned_objects = temp_unassigned_objects;
    }
    void HMMatcher::ComputeAssociationMat(
        const std::vector<RadarTrackPtr> &radar_tracks,
        const base::Frame &radar_frame,
        const std::vector<size_t> &unassigned_tracks,
        const std::vector<size_t> &unassigned_objects,
        std::vector<std::vector<double>> *association_mat) {
      double frame_timestamp = radar_frame.timestamp;
      for (size_t i = 0; i < unassigned_tracks.size(); ++i) {
        for (size_t j = 0; j < unassigned_objects.size(); ++j) {
          const base::ObjectPtr &track_object =
              radar_tracks[unassigned_tracks[i]]->GetObs();
          const base::ObjectPtr &frame_object =
              radar_frame.objects[unassigned_objects[j]];
          double track_timestamp =
              radar_tracks[unassigned_tracks[i]]->GetTimestamp();
          double distance_forward = DistanceBetweenObs(
              track_object, track_timestamp, frame_object, frame_timestamp);
          double distance_backward = DistanceBetweenObs(
              frame_object, frame_timestamp, track_object, track_timestamp);
          association_mat->at(i).at(j) =
              0.5 * distance_forward + 0.5 * distance_backward;
        }
      }
    }
    double HMMatcher::DistanceBetweenObs(const base::ObjectPtr &obs1,
                                         double timestamp1,
                                         const base::ObjectPtr &obs2,
                                         double timestamp2) {
      double time_diff = timestamp2 - timestamp1;
      return (obs2->center - obs1->center -
              obs1->velocity.cast<double>() * time_diff)
          .head(2)
          .norm();
    }
    

    ‘’‘
    ’‘’
    ‘’‘

    7:Camera和Radar融合算法

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    ’‘’
    ‘’‘
    ’‘’
    ‘’‘

    8:Lidar和Camera融合入算法

    #include <queue>
    #include <set>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    static const int MAX = 4;
    static const double maxC = 10001.f;
    
    vector< std::vector<double> > array_to_matrix(double* m, int rows, int cols);
    void hungarian_print_Costmatrix(const vector<vector<double> >& Cost);
    void hungarian_print_assignment(vector<int> &assignment);
    
    
    double c[MAX][MAX];
    double Fx[MAX];//Cost矩阵中每一行的最小值
    double Fy[MAX];//Cost矩阵中每一列的最小值
    int matchX[MAX];//初始化为-1|matchX[i]表示X中的第i个元素和Y[matchX[i]]产生配对关系
    int matchY[MAX];//初始化为-1|matchY[i]表示Y中的第i个元素和X[matchY[i]]产生配对关系
    int Trace[MAX];//初始化为-1
    int m;//tracks.size();
    int n;//detections.size();
    int k;//k=max(m,n)
    int start;
    int finish;
    
    
    double GetC(int i, int j);
    void FindAugmentingPath();
    void SubX_AddY();
    void Enlarge();
    void hungarian(vector<vector<double>>& DistMatrix, vector<int>& Assignment);
    
    int main()
    {
        //double r[3 * 3] =
        //{
        //	100,  300,   300,
        //	300,  100,   300,
        //	300,  300,   100
        //};
        double r[4 * 4] =
        {
            100,	100,	300,	300,
    
            300,	100,	100,	300,
    
            100,	100,	300,	300,
    
            300,	300,	100,	300
        };
        vector< vector<double> > Cost = array_to_matrix(r, 4, 4);
    
        hungarian_print_Costmatrix(Cost);
    
        vector<int> assignment;
        //Hungarian APS;
        //APS.Solve(Cost, assignment);
        hungarian(Cost, assignment);
    
        hungarian_print_assignment(assignment);
    
    
        return 0;
    }
    
    
    void hungarian(vector<vector<double>>& DistMatrix, vector<int>& Assignment)
    {
    
        int i, j;
        m = DistMatrix.size(); 
        n = DistMatrix[0].size(); 
    
        k = m > n ? m : n;//k=max(m,n)
    
                          //构建c矩阵,				  
        for (i = 0; i < k; i++)
        {
            for (j = 0; j < k; j++)
            {
                if (i >= m || j >= n)
                {
                    c[i][j] = maxC;//maxC = 10001.f|超过Cost矩阵范围的元素设为特别大
                    continue;
                }
                if (DistMatrix[i][j] == 0)
                    c[i][j] = maxC;//预测点与最新点的欧式距离为0的开销设为特别大
                else
                    c[i][j] = DistMatrix[i][j];
            }
        }
    
    
        for (i = 0; i < MAX; i++)
        {
            matchX[i] = -1;
            matchY[i] = -1;
        }
        //寻找Cost矩阵每一行的最小值
        for (i = 0; i < k; i++)
        {
            Fx[i] = maxC;
            for (j = 0; j < k; j++)
            {
                if (c[i][j] < Fx[i])
                {
                    Fx[i] = c[i][j];
                }
            }
        }
        //Cost矩阵的i行的每一个元素减去Fx[i],然后寻找每一列的最小值
        for (j = 0; j < k; j++)
        {
            Fy[j] = maxC;
            for (i = 0; i < k; i++)
            {
                if (c[i][j] - Fx[i] < Fy[j])
                {
                    Fy[j] = c[i][j] - Fx[i];
                }
            }
        }
    
    
    
        for (int x = 0; x < k; x++)
        {
        
            start = x;
            finish = -1;
            do
            {
                FindAugmentingPath();//利用0权重边寻找最大匹配
                if (finish == -1) 
                    SubX_AddY();//寻找最小点覆蓋集,调整边的权重
            } while (finish == -1);
            Enlarge();//在matchX、matchY中更新X和Y的配对关系
        }
    
    
        for (int x = 0; x < m; x++)
        {
            Assignment.push_back(matchX[x]);
        }
        for (int x = 0; x < m; x++)
        {
            for (int y = 0; y < n; y++)
            {
                DistMatrix[x][y] = c[x][y];
                if (c[x][y] == maxC)
                    DistMatrix[x][y] = 0.f;
            }
        }
        //计算损失函数值
        //float cost = 0.f;
        //for (int x = 0; x < m; x++)
        //{
        //	int y = matchX[x];
        //	if (c[x][y] < maxC)
        //	{
        //		cost += c[x][y];
        //	}
        //}
    
    }
    
    
    double GetC(int i, int j)
    {
        return c[i][j] - Fx[i] - Fy[j];
    }
    
    void FindAugmentingPath()
    {
        queue<int> q;
        int i, j;
    
        for (i = 0; i < MAX; i++)
        {
            Trace[i] = -1;
        }
        ///memset(Trace, -1, sizeof(Trace));
    
        //BFS宽度优先搜索|Running the algorithm BFS to find the opening of the road
        q.push(start);
    
        do
        {
            i = q.front();
            q.pop();
            for (j = 0; j < k; j++)
            {
                if (Trace[j] == -1 && GetC(i, j) == 0.0f)
                {
                    Trace[j] = i;
                    if (matchY[j] == -1)
                    {
                        finish = j;
                        return;
                    }
                    q.push(matchY[j]);
                }
            }
        } while (!q.empty());
    }
    
    void SubX_AddY()
    {
        int i, j, t;
        double Delta;
        set<int> VisitedX, VisitedY;
        
        VisitedX.insert(start);
        for (j = 0; j < k; j++)
        {
            if (Trace[j] != -1)
            {
                VisitedX.insert(matchY[j]);
                VisitedY.insert(j);
            }
        }
        
        Delta = maxC;
        for (i = 0; i < k; i++)
        {
            if (VisitedX.find(i) != VisitedX.end())
            {
                for (j = 0; j < k; j++)
                {
                    if ((VisitedY.find(j) == VisitedY.end()) && (GetC(i, j) < Delta))
                        Delta = GetC(i, j);
                }
            }
        }
    
        for (t = 0; t < k; t++)
        {
        
            if (VisitedX.find(t) != VisitedX.end())
                Fx[t] = Fx[t] + Delta;
            
            if (VisitedY.find(t) != VisitedY.end())
                Fy[t] = Fy[t] - Delta;
        }
    }
    
    void Enlarge()
    {
        int x, next;
        do
        {
            x = Trace[finish];
            next = matchX[x];
            matchX[x] = finish;
            matchY[finish] = x;
            finish = next;
        } while (finish != -1);
    }
    
    
    vector< std::vector<double> > array_to_matrix(double* m, int rows, int cols)
    {
        int i, j;
        std::vector< std::vector<double> > r;
        r.resize(rows, std::vector<double>(cols, 0));
    
        for (i = 0; i < rows; i++)
        {
            for (j = 0; j < cols; j++)
                r[i][j] = m[i*cols + j];
        }
        return r;
    }
    
    void hungarian_print_Costmatrix(const vector<vector<double> >& Cost)
    {
    
        int i, j;
        cout << endl;
        for (i = 0; i < Cost.size(); i++)
        {
            cout << "[";
            for (j = 0; j < Cost[0].size(); j++)
            {
                fprintf(stderr, "%-5.0f ", Cost[i][j]);
            }
            cout << "]" << endl;
        }
        cout << endl;
    
    }
    
    void hungarian_print_assignment(vector<int> &assignment)
    {
    
        for (int i = 0; i < assignment.size(); i++)
        {
            cout << assignment[i] << "  ";
        }//0 1 2
        cout << endl;
    
    }
    

    在这里插入图片描述

    9: 雷视融合应用定速巡航+车道保持

    请添加图片描述
    请添加图片描述
    请添加图片描述
    请添加图片描述
    请添加图片描述

    展开全文
  • 当前对视频的分析通常是基于...首先使用卷积神经网络对视频进行深度特征提取,然后基于传统手工方法提取内容特征,最后融合内容特征和深度特征提取关键.由实验结果可得本文方法相对以往关键提取方法有更好的表现.
  • 由于传统的边缘检测算法会产生信息漏...该算法与传统算法的结果比较表明该方法能清晰地检测出图像边缘点,图像的细节信息很好地保留下来,且对噪声图像具有一定的抗噪性,说明该算法是一种非常有效的图像边缘检测算法
  • 融合ViBe与差法的交叉路口车辆检测方法
  • 业分类-物理装置-一种融合注意力机制的多帧视频超分辨率方法.zip
  • 针对视频拷贝检测中检索速度问题,提出一种基于关键帧多特征融合的类局部敏感哈希索引方法,将存在拷贝片段的视频映射到同一个哈希桶中,减少检索的范围,达到提高检索速度的目的。该算法首先对视频进行镜头分割提取关键...
  • 常用的视频分割算法包括光流法、背景减除法和差法,但是3种算法容易受到计算量、环境噪声以及亮度突变等因素的影响,造成分割效果不理想。...实验表明,该融合算法可以实时的检测到视频中的运动物体,效果较好。
  • 电信设备-基于纹理信息重构的不同光照两图像融合方法.zip
  • 针对ViBe算法中鬼影消除缓慢的问题,结合个场景的交通视频提出一种通过连续两前景背景像素时域变化来判断鬼影像素点并消除的方法,该方法加快了鬼影的消除速度。同时,对于视频拍摄场景中的背景噪声,采用了对...
  • 采用了一种基于金字塔形小波变换(PDWFT)的图像融合方法,首先将配准好的源图像进行PDWFT分解,然后采用原始图像灰度的活跃度作为小波系数选取的参考标准,最后采用加权平均的融合方法并进行一致性验证得到最终的融合...
  • ViBe运动目标检测算法速度快,能有效抑制噪声,但在光照强度突然改变的情况下,该算法会造成大面积的背景像素被误判为前景像素,针对此问题提出一种改进的融合帧差法的ViBe算法。实验结果表明,改进的算法能在光照有...
  • 帧融合的功能(慢镜头的制作)

    千次阅读 2013-08-21 09:58:18
    帧融合的功能(慢镜头的制作)  2008-08-21 19:02:13| 分类: AE学习记录|字号 订阅 ...AE里的帧融合一直不觉得好,就是简单的帧与帧之间的叠画。前些天看了一个教程,发现这个帧融合还有两种算法,一个是叠

    转自:http://mc2109.blog.163.com/blog/static/253694620087217213706/

    帧融合的功能(慢镜头的制作)  

    2008-08-21 19:02:13|  分类: AE学习记录|字号 订阅

    AE里的帧融合一直不觉得好,就是简单的帧与帧之间的叠画。前些天看了一个教程,发现这个帧融合还有两种算法,一个是叠画方式,一个是像素运算的方式。今天来研究一下这两种之间的区别。

    首先,为什么要出现帧融合的功能?

    标准PAL电视信号是以每秒25幅画面进行记录和重放的,制作时,往往需要把镜头做慢速播放,也就是慢镜头。慢放时,原来的每秒25幅画面,被延长到大于一秒的播放时间上。比如慢放1倍,就是画面中运动物体的运动速度是实际的一半,每秒钟播放的画面就变成了12.5帧了。如果需要更慢,人眼就会察觉出画面在一格一格的变换,观看的效果就会出现停顿,画面中物体的运动不再是自然的平滑连续的了。因此,出现帧融合这样一个功能,目的是减轻慢放过程中的顿挫感。

    图中两个区域就是这个功能的开关。在层属性中,有三种状态,“空白”“左斜线”“右斜线”。分别代表帧融合功能关闭、帧混合、像素混合。如果想使这个功能起作用,还要打开上面的总开关。

    在运算的复杂度上,由上至下越来越复杂。也就意味着一个比一个更加费时间。

    另一种打开此功能的方法:

    在实际工作中,我们都希望获得非常平滑的慢动作效果。

    然而图像的获取有多种方法,实现平滑慢动作的方法也不相同。

    对于实拍的图像,最好使用前期设备直接获取。也就是提高拍摄时的帧率。

    目前,常用的方法就是胶片摄影机的升格拍摄,由于机器性能的差异,可以拍摄到的最高格数不一样。使用这样的设备,成本非常高。这也是最早实现慢动作的方法之一。

    还有一种方法,就是高速摄像机,这是可变帧频的摄像机,与普通摄像机最大的区别就是可以提高每秒拍摄的帧数。我见过用于科学研究领域的高速摄像头,是用来拍摄撞车实验的。每秒1000帧的速度。用于影视拍摄的高速摄像机要比这种摄像头更好。这种摄像机的租用费也比较贵。

    除去上面说的两种前期拍摄方法,可以获得完美的慢动作效果,再有的手段就是后期的帧融合了。效果较差,不能慢放太多,否则痕迹明显,效果极差。

    如果图像的来源是通过电脑生成的,那就好办了,直接在工作软件中放慢运动速度生成就可以了。

    在AE中制作的动画,使用单色层、文字层等制作的运动,只要不输出成影片素材,在AE中,直接改变播放速度,都可以获得平滑的慢放效果。

     

    实验总结:

    1 使用一段实拍的素材(鸽子飞起),进行慢放,打开像素融合,结果生成的中间帧使画面出现扭曲,慢放越多这样的扭曲越明显。

    改用帧融合,效果也不好,能看到明显的叠画痕迹。

    印证了实拍还是要使用前期的方法,才能获得较好的慢动作效果。这种后期的方法,只能简单的使用一下,不能作为高质量制作的手段。

    前几年,出现过专门的慢动作插件,也曾经试用过,效果和上面提到的像素融合差不多。

    这种像素融合的方法,适合图像层次简单、色彩单一、运动简单的个别实拍图像中,可以获得相对满意的效果。但是这样的实拍图像,在实际工作中,还是很少碰到的。

    手头正好有胶片升格实拍的素材,想看看这样的素材,在后期再做慢放的效果如何。结果令人满意。得出的结论就是:使用像素融合的图像,原始素材相邻两帧之间的变化越小,运算的结果越精确。完成的影片效果越好。

    展开全文
  • 曝光图像的融合算法实现 研究的目的 曝光图像融合是图像融合的一个重要分支,由于在 同一场景不同光线下得到的图像,无论它的曝光时间长短 都会出现曝光过度或曝光不足的现象,很容易在图像中产 生阴影及光照不均等...
  • “自动泊车、公路巡航控制和自动紧急制动等自动...只有把个传感器信息融合起来,才是实现自动驾驶的关键。”   现在路面上的很汽车,甚至是展厅内的很新车,内部都配备有基于摄像头、雷达、超声波或LIDAR...

    “自动泊车、公路巡航控制和自动紧急制动等自动驾驶汽车功能在很大程度上是依靠传感器来实现的。重要的不仅仅是传感器的数量或种类,它们的使用方式也同样重要。目前,大多数路面上行驶车辆内的ADAS都是独立工作的,这意味着它们彼此之间几乎不交换信息。只有把多个传感器信息融合起来,才是实现自动驾驶的关键。”

     

    现在路面上的很多汽车,甚至是展厅内的很多新车,内部都配备有基于摄像头、雷达、超声波或LIDAR等不同传感器的先进驾驶员辅助系统(ADAS)。

     

    这些系统的数量将会随着新法案的通过而不断增加,例如在美国,就有强制要求安装后视摄像头的法案。此外,诸如车险打折优惠和美国公路交通安全管理局(NHTSA)、欧洲新车安全评鉴协会(Euro-NCAP)等机构做出的汽车安全评级正在使某些系统成为汽车的强制功能;另一方面,这也助长了消费者对它们的需求。

     

    诸如自动泊车、公路巡航控制和自动紧急制动的自动驾驶汽车功能也在很大程度上依靠传感器来实现。重要的不仅仅是传感器的数量或种类,它们的使用方式也同样重要。目前,大多数路面上行驶车辆内的ADAS都是独立工作的,这意味着它们彼此之间几乎不交换信息。(没错,某些高端车辆具有非常先进的自动驾驶功能,不过这些功能还未普及)。后视摄像头、环视系统、雷达和前方摄像头都有它们各自的用途。通过将这些独立的系统添加到车辆当中,可以为驾驶员提供更多信息,并且实现自动驾驶功能。不过,你还可以突破限制,实现更多功能——参见图1。

    640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

    图1:ADAS以汽车内单个、独立的功能存在。

    传感器融合

     

    仅仅通过多次使用相同种类的传感器无法克服每种传感器的缺点。反之,我们需要将来自不同种类传感器的信息组合在一起。工作在可见光谱范围内的摄像头CMOS芯片在浓雾、下雨、刺眼阳光和光照不足的情况下会遇到麻烦。而雷达缺少目前成像传感器所具有的高分辨率。我们可以在每种传感器中找到诸如此类的优缺点。

     

    传感器融合这一想法的伟大之处在于获得不同传感器和传感器种类的输入内容,并且使用组合在一起的信息来更加准确地感知周围的环境。相对于独立系统,这样可以做出更好、更安全的决策。雷达也许不具有光传感器所具有的分辨率,不过它在测距和穿透雨、雪和浓雾方面具有很大优势。这些天气条件或光照不足的恶劣情况不利于摄像头发挥作用,不过摄像头能够分辨颜色(可以想一想街道指示牌和路标),并且具有很高的分辨率。目前路面上图像传感器的分辨率已经达到1百万像素。在未来几年内,图像传感器的发展趋势将是2百万,甚至4百万像素。

     

    雷达和摄像头是两项传感器技术完美融合、互为补充的典范。采用这种方法的融合系统所实现的功能要远超这些独立系统能够实现的功能总和。使用不同的传感器种类可以在某一种传感器全都出现故障的环境条件下,额外提供一定冗余度。这种错误或故障可能是由自然原因(诸如一团浓雾)或是人为现象(例如对摄像头或雷达的电子干扰或人为干扰)导致。即使是在一个传感器失效的情况下,这样的传感器融合系统也可以保持某些基本或紧急的功能。完全借助报警功能,或者让驾驶员时刻做好准备,从而接管对车辆的控制,系统故障也许就不那么严重了。然而,高度和完全自动驾驶功能必须提供充足的时间让驾驶员重新获得对车辆的控制。在这段驾驶员接管车辆控制之前的时间范围内,控制系统需要保持对车辆最低限度的控制。

     

    传感器融合系统示例

     

    传感器融合的复杂程度有所不同,并且数据的类型也不一样。两个基本的传感器融合示例是:a)后视摄像头加上超声波测距;b)前方摄像头加上多模式前置雷达——参见图2。现在,我们可以通过对现有系统进行轻微更改和/或通过增加一个单独的传感器融合控制单元来对其进行实现。

    640?wx_fmt=jpeg

    图2:将前方雷达与前方摄像头融合在一起,以实现自适应巡航控制加车道保持辅助,或者将后视摄像头与超声波测距报警组合在一起来实现自动泊车。

    • 后视摄像头+超声波测距

    超声波泊车辅助技术在汽车市场内被广泛接受,并且已十分成熟;这项技术在泊车时能对邻近物体给出听得见或看得见的报警。正如之前提到的那样,到2018年,美国所有新出厂的车辆都必须安装后视摄像头。将来自二者的信息结合在一起,才能实现先进的泊车辅助功能,而其靠单一系统是无法实现的。后视摄像头使驾驶员能很清楚地看到车辆后方的情况,而机器视觉算法可以探测物体,以及路肩石和街道上的标记。通过超声波提供的补充功能,可以准确确定识别物体的距离,并且在低光照或完全黑暗的情况下,也能确保基本的接近报警。

    • 前视摄像头+多模前置雷达

    另一种强大的组合是将前视摄像头的功能与前置雷达组合在一起。前置雷达能够在任何天气条件下测量高达150米的物体的速度和距离。摄像头在探测和区分物体方面(包括读取街道指示牌和路标)十分出色。通过使用具有不同视场角(FoV)和不同光学元件的多个摄像头传感器,系统可以识别车前通过的行人和自行车,以及150米甚至更远范围内的物体,同时,其还可以可靠实现自动紧急制动和城市启停巡航控制等功能。

    许多情况下,在特定的已知外部条件下,仅通过一种传感器或单个系统,就能够执行ADAS功能。然而,考虑到路面上有很多不可预计的情况,这还不足实现可靠运行。传感器融合除了能实现更复杂和自主的功能外,还可以在现有功能中实现更少的误报和漏报。说服消费者和立法者,使他们相信汽车可以由“一台机器”自主驾驶,将会十分关键。

    传感器融合系统分割

     

    与汽车内每个系统单独执行各自的报警或控制功能不同,在一个融合系统中,最终采取哪种操作是由单个器件集中决定的。现在的关键问题就是在哪里完成数据处理,以及如何将传感器的数据发送到中央电子控制单元(ECU)。当对不是集中在一起而是遍布车身的多个传感器进行融合时,我们就需要专门考虑传感器和中央融合ECU之间的连接和电缆。对于数据处理的位置也是如此,因为它也会影响整个系统的实现。让我们来看一看可能的系统分割中的两种极端情况。

    ·  集中式处理

     

    集中式处理的极端情况是,所有的数据处理和决策制定都是在同一个位置完成,数据是来自不同传感器的“原始数据”——请见图3。

    640?wx_fmt=jpeg

    图3:具有“传统”卫星式传感器模块的集中处理。

    优点:

    传感器模块——传感器模块体积小巧,成本低,功耗也低,这是因为其只需要执行检测和数据传输任务。传感器的安装位置也很灵活,并且所需安装空间很小。替换成本低。通常情况下,由于无需处理或做决策,传感器模块具有较低的功能安全要求。

    处理ECU——中央处理ECU可以获取全部数据,这是因为数据不会因为传感器模块内的预处理或压缩而丢失。由于传感器成本较低,并且外形尺寸较小,因此可以部署更多的传感器。

    缺点:

    传感器模块——实时处理传感器数据需要提供宽带通信(高达数Gb/s),因此可能出现较高电磁干扰(EMI)。

    处理ECU——中央ECU需要有高处理能力和速度来处理所有输入数据。对于很多高带宽I/O和高端应用处理器来说,这意味着更高的电能需求和更大的散热量。传感器数量增加将大幅增加对中央ECU性能的需要。通过使用FPD-Link III等接口,在一根同轴电缆上传送传感器及功耗、控制和配置等多种数据(双向反向通道),有些缺点可以被克服。这样便可极大降低系统的接线要求。

    · 全分布式系统

     

    另一种截然不同的极端情况是全分布式系统。这种情况是由本地传感器模块进行高级数据处理,并在一定程度上进行决策制定的。全分布式系统只将对象数据或元数据(描述对象特征和/或识别对象的数据)发回到中央融合ECU。ECU将数据组合在一起,并最终决定如何执行或做出反应——请见图4。

    640?wx_fmt=jpeg

    图4:传感器数据由传感器模块处理、决策由中央ECU制定的分布式系统。

    全分布式系统既有优点又有缺点。

    优点:

    传感器模块——传感器模块与中央ECU之间可以使用更低带宽、更加简单且更加便宜的接口。在很多情况下,小于1Mb/s的CAN总线就足够用了。

    处理ECU——中央ECU只将对象数据融合在一起,因此其所需处理能力更低。对于某些系统来说,用一个高级的安全微控制器就足够了。模块更小,所需功耗也就更低。由于很多处理都是在传感器内部完成的,传感器数量增加不会大幅增加对中央ECU的性能需求。

    缺点:

    传感器模块——传感器模块需要有应用处理器,这样的话就会变得体积更大、价格更高且功耗更大。由于本地处理和决策制定,传感器模块的功能安全要求也就更高。当然,增加更多的传感器,成本也会大幅上升。

    处理ECU——中央决策制定ECU只能获取对象数据,而无法访问实际的传感器数据。因此,想要“放大”感兴趣的区域很难实现。

    寻找黄金分割

     

    根据系统中所使用传感器的数量与种类,以及针对不同车型和升级选项的可扩展性要求,将两个拓扑混合在一起就可获得一个优化解决方案。目前很多融合系统使用带本地处理的传感器用于雷达和激光雷达(LIDAR),使用前置摄像头用于机器视觉。一个全分布式系统可以使用现有的传感器模块与对象数据融合ECU组合在一起。诸如环视和后视摄像头的系统中的“传统”传感器模块可以让驾驶员看到周围的环境情况——请见图5。可以将更多的ADAS功能集成进驾驶员监测或摄像头监控系统等融合系统中,但是传感器融合的原理还是一样。

    640?wx_fmt=jpeg

    图5:寻找分布式和集中式处理的完美结合。

    平台管理、目标汽车细分、灵活性和可扩展性是重要的经济因素;这些因素也在分割和设计融合系统时发挥着重要作用。对于任一特定情况,所得系统也许不是最佳设计方案,但是从平台和车队的角度看,它却可能是最佳方案。

    谁是所有这些传感器数据的“观看者”?

     

    关于ADAS,我们还有两个方面没有讨论到:信息ADAS对功能ADAS。前者就是当驾驶员仍然对汽车完全掌控时,扩大和延伸驾驶员的感官范围(例如环视和夜视)。第二个是机器视觉,它使汽车能够感知周围环境,并做出自我决策以及执行(自动紧急制动、车道保持辅助)。传感器融合自然而然地将这两个世界合而为一。

    正因如此,我们才有可能将同一传感器应用于不同用途,不过这么做的代价就是在选择最佳模块间通信和处理位置方面受到了限制。以环视为例,这项功能最初的设计目的是,通过将视频传入到中央显示屏上,为驾驶员提供360度视场角。为什么不使用同样的摄像头,并将机器视觉应用到其上呢?后视摄像头可用于实现倒车保护或自动停车,而侧视摄像头可用于实现盲点检测/报警,也包括自动泊车。

    单独使用的机器视觉在传感器模块内进行本地处理,然后通过CAN总线等简单的低带宽连接将对象数据甚至是命令传送出去。然而,这种连接不足以传送完整的视频流。视频压缩当然可以降低所需带宽,但是还不足以将所需带宽降到百兆位范围内,并且它本身也存在一些问题。随着高动态范围(HDR)分辨率、帧速率和曝光数增加,这变得更加困难。高带宽连接和摄像头模块不参与数据处理解决了视频的问题,但是现在需要将处理添加到中央ECU,以便在其中运行机器视觉。缺少中央处理能力或散热控制会成为这种解决方案的瓶颈。

    虽然在传感器模块中进行处理并同时使用高带宽通信在技术上并不是不可实现,但从总体系统成本、功耗和安装空间角度来讲并不十分有利。

    传感器融合配置的可靠运行

     

    由于很多融合系统能够在没有驾驶员的情况下执行特定汽车功能(例如转向、制动和加速)的自主控制,我们需要对功能安全进行认真考虑,以确保在不同条件下和汽车的使用寿命内系统能够安全和可靠运行。一旦做出决策,并随后采取自主操作,那么对于功能安全的要求将会大幅提升。

    若采用分布式的方法,每个处理关键数据或制定决策的模块必须符合那些增加的标准。与只搜集和发送传感器信息的模块相比,这会增加物料清单(BOM)成本、尺寸、功耗和软件。在安装空间不足的环境中,器件很难冷却,并且其损坏的风险和所需的更换也很高(一次简单的小事故有可能需要更换保险杠和所有相连的传感器),这可能抵消具有多个传感器模块的分布式系统的优势。

    如果采用“传统”传感器模块,则需进行自检和故障报告,以实现整个系统的安全运转,但是其还未达到智能传感器模块的程度。

    虽然纯粹的驾驶员信息系统可以在它们的功能受到损害时关闭并将其通报给驾驶员,但是高度自主驾驶功能就没有那么自由了。想象一下一辆汽车正在执行紧急制动操作,然后又突然解除并松开制动器的情况。或者说,汽车在公路上行驶时,整个系统关闭,而此时驾驶员正在汽车“全自动驾驶”状态下呼呼大睡(未来可能的一个场景)。在驾驶员能够安全控制车辆之前,系统需要继续保持工作一段时间,而这至少需要有几秒到半分钟。系统必须运行到何种程度,以及如何确保在故障情况下运转,这些问题在业内似乎还未达成明确共识。具有自动驾驶功能的飞机通常情况下使用冗余系统。虽然我们一般情况下认为它们是安全的,不过它们造价昂贵并且占用大量空间。

    传感器融合将会是迈向自动驾驶及享受旅途时光和驾驶乐趣的关键一步。

    多传感器信息融合算法

    智能汽车的显著特点在于智能,意思就是说汽车自己能通过车载传感系统感知道路环境,自动规划行车路线并控制车辆到达预定目标。目前而言,车载感知模块包括视觉感知模块、毫米波雷达、超声波雷达、360°环视系统等,多源传感器的协同作用识别道路车道线、行人车辆等障碍物,为安全驾驶保驾护航。因此,感知信息也需要融合,感知信息也需要相互补充。

     

    这里引出一个重要的概念:多传感器信息融合(information fusion)。各种不同的传感器,对应不同的工况环境和感知目标。比方说,毫米波雷达主要识别前向中远距离障碍物(0.5米-150米),如路面车辆、行人、路障等。超声波雷达主要识别车身近距离障碍物(0.2米-5米),如泊车过程中的路沿、静止的前后车辆、过往的行人等信息。两者协同作用,互补不足,通过测量障碍物角度、距离、速度等数据融合,刻画车身周边环境和可达空间范围。

     

     

    640?wx_fmt=jpeg

     

    图6:智能汽车感知模块

     

    信息融合起初叫做数据融合(data fusion),起源于1973年美国国防部资助开发的声纳信号处理系统,在20世纪90年代,随着信息技术的广泛发展,具有更广义化概念的“信息融合”被提出来,多传感器数据融合MSDF (Multi-sensor Data Fusion)技术也应运而生。

     

    数据融合主要优势在于:充分利用不同时间与空间的多传感器数据资源,采用计算机技术按时间序列获得多传感器的观测数据,在一定准则下进行分析、综合、支配和使用。获得对被测对象的一致性解释与描述,进而实现相应的决策和估计,使系统获得比它各组成部分更为充分的信息。

     

    一般地,多源传感器数据融合处理过程包括六个步骤,如下图所示。首先是多源传感系统搭建与定标,进而采集数据并进行数字信号转换,再进行数据预处理和特征提取,接着是融合算法的计算分析,最后输出稳定的、更为充分的、一致性的目标特征信息。

     

    640?wx_fmt=jpeg

    图7:多源数据融合过程

     

    利用多个传感器所获取的关于对象和环境全面、完整信息,主要体现在融合算法上。因此,多传感器系统的核心问题是选择合适的融合算法。对于多传感器系统来说,信息具有多样性和复杂性,因此,对信息融合方法的基本要求是具有鲁棒性和并行处理能力,以及方法的运算速度和精度。以下简要介绍三种种常用的数据融合算法,包括贝叶斯统计理论,神经网络技术,以及卡尔曼滤波方法。

     

    贝叶斯统计理论

     

    640?wx_fmt=jpeg

    图8:文氏图

     

    英国数学家托马斯·贝叶斯(Thomas Bayes)在1763年发表的一篇论文中,首先提出了这个定理。贝叶斯统计理论是一种统计学方法,用来估计统计量的某种特性,是关于随机事件A和B的条件概率的一则定理。所谓"条件概率"(Conditional probability),就是指在事件B发生的情况下,事件A发生的概率,用P(A|B)来表示。根据上述文氏图,容易推导得到:P(A ∩ B) = P( A | B) * P(B) = P( B | A) * P(A),由此可以推导出条件概率的公式,其中我们把P(A)称为先验概率(Prior probability),即在事件B发生之前,我们对事件A发生概率有一个认识。

    640?wx_fmt=jpeg

    举个简单的例子,视觉感知模块中图像检测识别交通限速标志(Traffic Sign Recognition, TSR )是智能驾驶的重要一环。TSR识别过程中,交通限速标志牌被树木,灯杆等遮挡是影响识别的主要干扰。那么我们关心的,是交通限速标志被遮挡的情况下,检出率有多少呢?这里我们定义事件A为交通信号标志正确识别,事件为交通信号标志未能识别;B为限速标志被遮挡,事件为限速标志未被遮挡。

     

    640?wx_fmt=jpeg

    图9:被遮挡的交通限速标志

     

    根据现有算法,可以统计出事件A正确识别交通限速标志的概率,此处事件A的概率称为先验概率。通过查看视觉感知模块的检测视频录像,我们可以统计检测出来的交通限速标志中有多少被遮挡,有多少是没被遮挡的,还可以统计漏检的交通限速标志中,有多少是被遮挡的,有多少是没被遮挡的。因此,我们可以得到下面值:

    640?wx_fmt=jpeg

    由此,可以推算出被遮挡的情况下,正确识别限速标志的概率:

    640?wx_fmt=jpeg

    那么,也有人可能会问,如果限速标志没有被遮挡,识别率有多高呢?同理,我们这里也可以一并计算:

    640?wx_fmt=jpeg

    从以上计算我们可以看到,限速标志未被遮挡完全暴露出来,识别率是相当高的,但如果限速标记牌被阻挡住,识别率是比未遮挡的低很多。这两个指标的融合使用,可以用于作为评价目前图像处理算法识别限速标志性能的重要参考。当然,实际的融合过程比这复杂得多,小鹏汽车工程师们正努力不断优化,提高各种工况下的识别率,提供更为舒适的智能驾驶辅助。

     

    神经网络理论

     

    640?wx_fmt=jpeg

    图9:神经网络

     

    神经网络(Artificial Neural Network,ANN)是机器学习(Machine Learning,ML)的其中一种方式,是人工智能、认知科学、神经生理学、非线性动力学、信息科学、和数理科学的“热点”。

     

    ANN的发展经历了三个阶段

     

    • 第一个阶段是起步阶段,从20世纪40年代开始逐渐形成了一个新兴的边缘性交叉学科。1943年,心理学家McCulloch和数学家Pitts合作,融汇了生物物理学和数学,提出了第一个神经计算模型: MP模型。1949年,心理学家Hebb通过对大脑神经细胞、学习和条件反射的观察与研究,提出了改变神经元连接强度的、至今仍有重要意义的Hebb规则。

       

    • 第二阶段是发展阶段,1957年,Rosenblatt发展了MP模型,提出了感知器模型:Perception Model,给出了两层感知器的收敛定理,并提出了引入隐层处理元件的三层感知器这一重要的研究方向。1960年,Widrow提出自适应线性元件模型:Ada-line model以及一种有效的网络学习方法:Widrow-Hoff学习规则。

       

    • 第三阶段是成熟阶段,1982年美国加州工学院的物理学家Hopfield提出了一个用于联想记忆和优化计算的新途径——Hopfield网络,使得神经网络的研究有了突破性进展。1984年在Hopfield的一篇论文中,指出Hopfield网络可以用集成电路实现,很容易被工程技术人员和计算机科技工作者理解,引起工程技术界的普遍关注。

     

    上世纪八十年代后期,神经网络的光芒被计算机技术、互联网掩盖了,但这几年计算机技术的发展,恰恰给神经网络更大的机会。神经网络由一层一层的神经元构成。层数越多,就越深,所谓深度学习(Deep Learning)就是用很多层神经元构成的神经网络达到机器学习的功能。辛顿是深度学习的提出者,2006年,基于深度置信网络(DBN)提出非监督贪心逐层训练算法,为解决深层结构相关的优化难题带来希望,随后提出多层自动编码器深层结构。目前,深度学习的神经网络技术广泛用于计算机视觉、语音识别、自然语言处理识别上。

     

    关于神经网络的研究包含众多学科领域,涉及数学、计算机、人工智能、微电子学、自动化、生物学、生理学、解剖学、认知科学等学科,这些领域彼此结合、渗透,相互推动神经网络研究和应用的发展。

     

    640?wx_fmt=jpeg

    图10:一个人工神经细胞

     

    接着,简单介绍下神经网络的基础。生物的大脑是由许多神经细胞组成,同样,模拟大脑的人工神经网络ANN是由许多叫做人工神经细胞(Artificial neuron,也称人工神经原,或人工神经元)的细小结构模块组成。人工神经细胞就像真实神经细胞的一个简化版,如图所示,左边几个蓝色圆中所标字母w代表浮点数,称为权重(weight,或权值,权数)。进入人工神经细胞的每一个input(输入)都与一个权重w相联系,正是这些权重将决定神经网络的整体活跃性。你现在暂时可以设想所有这些权重都被设置到了-1和1之间的一个随机小数。因为权重可正可负,故能对与它关联的输入施加不同的影响,如果权重为正,就会有激发(excitory)作用,权重为负,则会有抑制(inhibitory)作用。当输入信号进入神经细胞时,它们的值将与它们对应的权重相乘,作为图中大圆的输入。大圆的‘核’是一个函数,叫激励函数(activation function),它把所有这些新的、经过权重调整后的输入全部加起来,形成单个的激励值(activation value)。激励值也是一浮点数,且同样可正可负。然后,再根据激励值来产生函数的输出也即神经细胞的输出:如果激励值超过某个阀值(作为例子我们假设阀值为1.0),就会产生一个值为1的信号输出;如果激励值小于阀值1.0,则输出一个0。这是人工神经细胞激励函数的一种最简单的类型。

     

    640?wx_fmt=jpeg

    图11:神经网络结构

     

    大脑里的生物神经细胞和其他的神经细胞是相互连接在一起的。为了创建一个人工神经网络,人工神经细胞也要以同样方式相互连接在一起。为此可以有许多不同的连接方式,其中最容易理解并且也是最广泛地使用的,就是如图所示那样,把神经细胞一层一层地连结在一起。这一种类型的神经网络就叫前馈网络(feed forward network)。这一名称的由来,就是因为网络的每一层神经细胞的输出都向前馈送(feed)到了它们的下一层(在图中是画在它的上面的那一层),直到获得整个网络的输出为止。

     

    神经细胞通过输入层、隐含层和输出层的链接,形成一个复杂的神经网络系统,通过有效的学习训练,使输出层的结果与现实越来越靠近,误差越来越小,当其精度满足一定的功能需求时,神经网络训练完毕,此刻构建的神经网络系统即能为我们解决众多机器学习上的图像识别、语音识别、文字识别上的问题。

     

    在智能驾驶目前的发展历程上看,人工神经网络技术,乃至现在最新的深度学习技术,广泛用于视觉感知模块的车辆识别、车道线识别、交通标志识别上。通过对中国路况工况的数据采集和处理,广泛获取国内不同天气状况(雨天、雪天、晴天等),不同路况(城市道路、乡村道路、高速公路等)的真实的环境数据,为深度学习提供了可靠的数据基础。此处神经网络的输入层数据,也即是传感器获取的数据,是多源多向的,可以是前挡风玻璃片上视觉感知模块的障碍物位置、形状、颜色等信息,也可以是毫米波雷达、超声波雷达检测的障碍物距离、角度、速度、加速度等信息,还可以是360°环视系统上采集的车位数据、地面减速带数据。

     

    卡尔曼滤波

     

    卡尔曼滤波(Kalman filtering)一种利用线性系统状态方程,通过系统输入输出观测数据,对系统状态进行最优估计的算法。简单来说,卡尔曼滤波器是一个“optimal recursive data processing algorithm(最优化自回归数据处理算法)”。对于解决很大部分的问题,它是最优,效率最高甚至是最有用的。Kalman滤波在测量方差已知的情况下能够从一系列存在测量噪声的数据中,估计动态系统的状态。由于,它便于计算机编程实现,并能够对现场采集的数据进行实时的更新和处理, Kalman滤波是目前应用最为广泛的滤波方法,在通信、导航、制导与控制等多领域得到了较好的应用。
     

    卡尔曼滤波是多源传感数据融合应用的重要手段之一,为了扼要地介绍卡尔曼滤波的原理,此处形象地用毫米波雷达与视觉感知模块融合目标位置的过程描述。举一个简单的例子,目前高级辅助驾驶系统(Advanced Driver Assistance System,ADAS)上,搭载有毫米波雷达和超声波雷达模块,两者均能对障碍物车辆进行有效的位置估计判别。雷达利用主动传感原理,发射毫米波,接收障碍物回波,根据波传播时间计算角度距离。两者均能识别出车辆位置,那么我们该如何融合信息,如何取舍,计算出具体的车辆位置呢?卡尔曼正是解决这个问题的方法之一。我们获取的车辆位置在任何时刻都是有噪声的,卡尔曼滤波利用目标的动态信息,设法去掉噪声的影响,得到一个关于目标位置的好的估计。这个估计可以是对当前目标位置的估计(滤波),也可以是对于将来位置的估计(预测),还可以是对过去位置的估计(插值或平滑)。卡尔曼滤波就是这样一个根据当前时刻目标的检测状态,预测估计目标下一时刻目标检测状态的一个动态迭代循环过程。

     

    高级辅助驾驶系统ADAS是目前智能汽车发展的重要方向,其手段是通过多源传感器信息融合,为用户打造稳定、舒适、可靠可依赖的辅助驾驶功能,如车道保持系统(Lane Keeping Assist, LKA),前碰预警(Forward Collision Warning, FCW),行人碰撞警告(Pedestrian Collision Warning,PCW),交通标记识别(Traffic Sign Recognition,TSR),车距监测报告(Head Monitoring and Warning,HMW)等。多源信息的融合,目的在于数据信息的冗余为数据信息的可靠分析提供依据,从而提高准确率,降低虚警率和漏检率,实现辅助驾驶系统的自检和自学习,最终实现智能驾驶、安全驾驶的最终目标。

    ▎本文转自电子技术设计,知乎小鹏汽车,作者:Hannes Estl,德州仪器(TI)汽车ADAS部门的总经理,如需转载请注明来源。

    --------------------- 本文来自 人人都是极客 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/p23onzq/article/details/79257269?utm_source=copy

    展开全文
  • 采用改进的间差分法,融合分水岭算法分割特点,获得真实目标的轮廓,并进行实验验证。结果表明,该算法差法进行改进后,得到的动态目标更接近于实际情况,改进的算法更适合于智能系统中消除杂波及对运动目标的...
  • 利用电荷耦合器件(CCD)在一定范围内与光照度成线性响应的特性,提出了一种通过双图像融合方法,进行脉冲激光束散角的检测,并通过Matlab数学仿真和实验验证了其可行性和准确性。该方法扩大了光照度适用范围;...
  • 针对多帧低分辨率图像重建问题,提出了基于稀疏编码和随机森林的超分辨率算法。首先,使用高分辨率训练图像和低分辨率训练图像获取高分辨率字典;然后,使用重叠块缓解块边界的振铃现象,并使用反向投影保证全局一致...
  • 针对现有煤料分割方法中轮廓检测不全,边缘残缺以及环境自适性差等问题,提出一种四差分与局部熵融合的煤流分割方法,根据煤流轮廓面积特征来检测溜槽处是否发生堵塞。首先引入间差分法的思想,提取运动状态的煤流...
  • 多帧SR算法是一种张存在很小位移的LR 图,通过特定算法最终获得一幅HR图。其中获取张LR图片通过移动sensor的方法(即sensor shift技术)来...传统的多帧超分算法主要采用的方法有KERNEL REGRESSION的方法,其中代
  • 多帧去躁matlab

    2017-10-19 10:15:27
    使用时域多帧融合可以极大的改善暗光下的成像质量,但相机的抖动和运动物体给具体应用带来了挑战,本算法通过光流可以有效的避免鬼影的出现,极大的提高成像质量,去躁效果十分明显

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,881
精华内容 7,952
关键字:

多帧融合算法