多传感器融合定位:基于滤波的融合方法

2023-05-16

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

SLAM 后端的优化方式大体分为滤波和优化。近些年优化越来越成为主流,在学习优化之前,掌握滤波的工作原理也十分必要。

一、引言

滤波问题可以简单理解为“预测 +观测 =融合结果”。

结合实际点云地图中定位的例子,预测由IMU给出,观测即为激光雷达点云和地图匹配得到的姿态和位置。

融合流程用框图可以表示如下

82849f5d2dfcc79dbc8990edc57a1e6e.png

简述kalman滤波:

为了避免复杂的公式推导,大多数只给出结论:

贝叶斯滤波

贝叶斯滤波的信息流图如下:

9ab5146c1be0dd11c6538ff9339ddb99.png 2681648bcd4e82be92ced582a34800ea.png

在高斯假设前提下,用贝叶斯滤波的原始形式推导比较复杂,可以利用高斯的特征得到简化形式,即广义高斯滤波。后面KF、EKF、IEKF的推导均采用这种形式。

卡尔曼滤波(KF)推导

0a1971c723fd902ba480cc8f815617e3.png 043b0ca08ead99878bc790d0e6a4a6da.png

二、基于滤波的融合

1.状态方程

644ef68119e006776cdca1566d45e895.png

2.观测方程

b65d6bfdd91bd7f17de9b703c3c7a921.png

3.构建滤波器

14db7dc0f07a1eb8641293a8724b703e.png

4.Kalman滤波实际使用流程

e63774fed2d8522da8f4253a75fe7c69.png

代码:

/**
 * @brief  init filter
 * @param  pose, init pose
 * @param  vel, init vel
 * @param  imu_data, init IMU measurements
 * @return true if success false otherwise
 */
void ErrorStateKalmanFilter::Init(const Eigen::Vector3d &vel,
                                  const IMUData &imu_data) {
  // init odometry:
  Eigen::Matrix3d C_nb = imu_data.GetOrientationMatrix().cast<double>();
  // a. init C_nb using IMU estimation:
  pose_.block<3, 3>(0, 0) = C_nb;
  // b. convert flu velocity into navigation frame:
  vel_ = C_nb * vel;

  // save init pose:
  init_pose_ = pose_;

  // init IMU data buffer:
  imu_data_buff_.clear();
  imu_data_buff_.push_back(imu_data);

  // init filter time:
  time_ = imu_data.time;

  // set process equation in case of one step prediction & correction:
  Eigen::Vector3d linear_acc_init(imu_data.linear_acceleration.x,
                                  imu_data.linear_acceleration.y,
                                  imu_data.linear_acceleration.z);
  Eigen::Vector3d angular_vel_init(imu_data.angular_velocity.x,
                                   imu_data.angular_velocity.y,
                                   imu_data.angular_velocity.z);
  // covert to navigation frame:
  linear_acc_init =  linear_acc_init - accl_bias_;            //  body 系下
  angular_vel_init = GetUnbiasedAngularVel(angular_vel_init, C_nb);

  // init process equation, in case of direct correct step:
  UpdateProcessEquation(linear_acc_init, angular_vel_init);

  LOG(INFO) << std::endl
            << "Kalman Filter Inited at " << static_cast<int>(time_)
            << std::endl
            << "Init Position: " << pose_(0, 3) << ", " << pose_(1, 3) << ", "
            << pose_(2, 3) << std::endl
            << "Init Velocity: " << vel_.x() << ", " << vel_.y() << ", "
            << vel_.z() << std::endl;
}


// 设置状态方程
void ErrorStateKalmanFilter::UpdateProcessEquation(
    const Eigen::Vector3d &linear_acc_mid,
    const Eigen::Vector3d &angular_vel_mid) {
  // set linearization point:
  Eigen::Matrix3d C_nb = pose_.block<3, 3>(0, 0);           //   n2b   转换矩阵
  Eigen::Vector3d f_b = linear_acc_mid + g_;                     //   加速度
  Eigen::Vector3d w_b = angular_vel_mid;                         //   角速度

  // set process equation:
  SetProcessEquation(C_nb, f_b, w_b);
}

/**
 * @brief  set process equation
 * @param  C_nb, rotation matrix, body frame -> navigation frame
 * @param  f_n, accel measurement in navigation frame
 * @return void
 */
void ErrorStateKalmanFilter::SetProcessEquation(const Eigen::Matrix3d &C_nb,                      //   更新状态方程  F矩阵
                                                const Eigen::Vector3d &f_b,
                                                const Eigen::Vector3d &w_b) {
  // TODO: set process / system equation:
  // a. set process equation for delta vel:
  F_.setZero();
  F_.block<3,  3>(kIndexErrorPos,  kIndexErrorVel)  =  Eigen::Matrix3d::Identity();
  F_.block<3,  3>(kIndexErrorVel,   kIndexErrorOri)  =  - C_nb *  Sophus::SO3d::hat(f_b).matrix();
  F_.block<3,  3>(kIndexErrorVel,   kIndexErrorAccel) =  -C_nb;
  F_.block<3,  3>(kIndexErrorOri,   kIndexErrorOri) =   - Sophus::SO3d::hat(w_b).matrix();
  F_.block<3,  3>(kIndexErrorOri,   kIndexErrorGyro) =   - Eigen::Matrix3d::Identity();
  // b. set process equation for delta ori:
  B_.setZero();
  B_.block<3,  3>(kIndexErrorVel,  kIndexNoiseGyro)  =    C_nb;
  B_.block<3,  3>(kIndexErrorOri,  kIndexNoiseGyro)  =     Eigen::Matrix3d::Identity();
  if(COV.PROCESS.BIAS_FLAG){      //  判断是否考虑随机游走
    B_.block<3,  3>(kIndexErrorAccel,  kIndexNoiseBiasAccel)  =     Eigen::Matrix3d::Identity();
    B_.block<3,  3>(kIndexErrorGyro,  kIndexNoiseBiasGyro)    =     Eigen::Matrix3d::Identity();
  }
}
d7b9fe39609de29045e9b22a9e15d827.png
// c. process noise:
  Q_.block<3, 3>(kIndexNoiseAccel, kIndexNoiseAccel) = COV.PROCESS.ACCEL * Eigen::Matrix3d::Identity();
  Q_.block<3, 3>(kIndexNoiseGyro, kIndexNoiseGyro) = COV.PROCESS.GYRO * Eigen::Matrix3d::Identity();
  if (COV.PROCESS.BIAS_FLAG ){
    Q_.block<3, 3>(kIndexNoiseBiasAccel, kIndexNoiseBiasAccel) = COV.PROCESS.BIAS_ACCEL * Eigen::Matrix3d::Identity();
    Q_.block<3, 3>(kIndexNoiseBiasGyro, kIndexNoiseBiasGyro) = COV.PROCESS.BIAS_GYRO * Eigen::Matrix3d::Identity();
  }
  // d. measurement noise:
  RPose_.block<3, 3>(0, 0) = COV.MEASUREMENT.POSE.POSI * Eigen::Matrix3d::Identity();
  RPose_.block<3, 3>(3, 3) = COV.MEASUREMENT.POSE.ORI * Eigen::Matrix3d::Identity();

  // e. process equation:
  F_.block<3, 3>(kIndexErrorPos, kIndexErrorVel) = Eigen::Matrix3d::Identity();
  F_.block<3, 3>(kIndexErrorOri, kIndexErrorGyro) = -Eigen::Matrix3d::Identity();

  B_.block<3, 3>(kIndexErrorOri, kIndexNoiseGyro) = Eigen::Matrix3d::Identity();
  B_.block<3, 3>(kIndexErrorAccel, kIndexNoiseBiasAccel) = Eigen::Matrix3d::Identity();
  B_.block<3, 3>(kIndexErrorGyro, kIndexNoiseBiasGyro) = Eigen::Matrix3d::Identity();

  // f. measurement equation:
  GPose_.block<3, 3>(0, kIndexErrorPos) = Eigen::Matrix3d::Identity();
  GPose_.block<3, 3>(3, kIndexErrorOri) = Eigen::Matrix3d::Identity();
  CPose_.block<3, 3>(0, 0) = Eigen::Matrix3d::Identity();
  CPose_.block<3, 3>(3, 3) = Eigen::Matrix3d::Identity();

  // init soms:
  QPose_.block<kDimMeasurementPose, kDimState>(0, 0) = GPose_;
d000ca3d2aac569ee0256e0e110b90e2.png

这部分是惯导解算的内容,在Updata()函数中:

在Updata()函数中有两个重要的函数,即UpdateOdomEstimation(),UpdateErrorEstimation(),分别做名义值更新和误差值更新

bool ErrorStateKalmanFilter::Update(const IMUData &imu_data) {
  //
  // TODO: understand ESKF update workflow
  //
  // update IMU buff:
  if (time_ < imu_data.time) {
    // update IMU odometry:
    Eigen::Vector3d linear_acc_mid;
    Eigen::Vector3d angular_vel_mid;
    imu_data_buff_.push_back(imu_data);
    UpdateOdomEstimation(linear_acc_mid, angular_vel_mid);  // 做名义值更新
    imu_data_buff_.pop_front();

    // update error estimation:
    double T = imu_data.time - time_;
    UpdateErrorEstimation(T, linear_acc_mid, angular_vel_mid);  // 做误差值更新

    // move forward:
    time_ = imu_data.time;

    return true;
  }

  return false;
}
42e40dc445f1e5b7413ae32503085f96.png

名义值状态量(位置、速度、姿态、陀螺仪bias、加计bias)更新函数:UpdateOdomEstimation(linear_acc_mid, angular_vel_mid):

void ErrorStateKalmanFilter::UpdateOdomEstimation(                  //  更新名义值 
    Eigen::Vector3d &linear_acc_mid, Eigen::Vector3d &angular_vel_mid) {
  //
  // TODO: this is one possible solution to previous chapter, IMU Navigation,
  // assignment
  //
  // get deltas:
    size_t   index_curr_  = 1;
    size_t   index_prev_ = 0;
    Eigen::Vector3d  angular_delta = Eigen::Vector3d::Zero();            
    GetAngularDelta(index_curr_,  index_prev_,   angular_delta,  angular_vel_mid);           //   获取等效旋转矢量,   保存角速度中值
  // update orientation:
    Eigen::Matrix3d  R_curr_  =  Eigen::Matrix3d::Identity();
    Eigen::Matrix3d  R_prev_ =  Eigen::Matrix3d::Identity();
    UpdateOrientation(angular_delta, R_curr_, R_prev_);                         //     更新四元数
  // get velocity delta:
    double   delta_t_;
    Eigen::Vector3d  velocity_delta_;
    GetVelocityDelta(index_curr_, index_prev_,  R_curr_,  R_prev_, delta_t_,  velocity_delta_,  linear_acc_mid);             //  获取速度差值, 保存线加速度中值
  // save mid-value unbiased linear acc for error-state update:

  // update position:
  UpdatePosition(delta_t_,  velocity_delta_);
}

惯导解算中,分别对应

1571f62320f00d0727aadbbead70d33f.png
//旋转向量解算:
bool ErrorStateKalmanFilter::GetAngularDelta(const size_t index_curr,
                                             const size_t index_prev,
                                             Eigen::Vector3d &angular_delta,
                                             Eigen::Vector3d &angular_vel_mid) {
  if (index_curr <= index_prev || imu_data_buff_.size() <= index_curr) {
    return false;
  }

  const IMUData &imu_data_curr = imu_data_buff_.at(index_curr);
  const IMUData &imu_data_prev = imu_data_buff_.at(index_prev);

  double delta_t = imu_data_curr.time - imu_data_prev.time;

  Eigen::Vector3d angular_vel_curr = Eigen::Vector3d(
      imu_data_curr.angular_velocity.x, imu_data_curr.angular_velocity.y,
      imu_data_curr.angular_velocity.z);
  Eigen::Matrix3d R_curr = imu_data_curr.GetOrientationMatrix().cast<double>();
  angular_vel_curr = GetUnbiasedAngularVel(angular_vel_curr, R_curr);

  Eigen::Vector3d angular_vel_prev = Eigen::Vector3d(
      imu_data_prev.angular_velocity.x, imu_data_prev.angular_velocity.y,
      imu_data_prev.angular_velocity.z);
  Eigen::Matrix3d R_prev = imu_data_prev.GetOrientationMatrix().cast<double>();
  angular_vel_prev = GetUnbiasedAngularVel(angular_vel_prev, R_prev);

  angular_delta = 0.5 * delta_t * (angular_vel_curr + angular_vel_prev);

  angular_vel_mid = 0.5 * (angular_vel_curr + angular_vel_prev);
  return true;
}

// 姿态解算
void ErrorStateKalmanFilter::UpdateOrientation(
    const Eigen::Vector3d &angular_delta, Eigen::Matrix3d &R_curr,
    Eigen::Matrix3d &R_prev) {
  // magnitude:
  double angular_delta_mag = angular_delta.norm();
  // direction:
  Eigen::Vector3d angular_delta_dir = angular_delta.normalized();

  // build delta q:
  double angular_delta_cos = cos(angular_delta_mag / 2.0);
  double angular_delta_sin = sin(angular_delta_mag / 2.0);
  Eigen::Quaterniond dq(angular_delta_cos,
                        angular_delta_sin * angular_delta_dir.x(),
                        angular_delta_sin * angular_delta_dir.y(),
                        angular_delta_sin * angular_delta_dir.z());
  Eigen::Quaterniond q(pose_.block<3, 3>(0, 0));

  // update:
  q = q * dq;

  // write back:
  R_prev = pose_.block<3, 3>(0, 0);
  pose_.block<3, 3>(0, 0) = q.normalized().toRotationMatrix();
  R_curr = pose_.block<3, 3>(0, 0);
}

//速度解算
bool ErrorStateKalmanFilter::GetVelocityDelta(
    const size_t index_curr, const size_t index_prev,
    const Eigen::Matrix3d &R_curr, const Eigen::Matrix3d &R_prev, double &T,
    Eigen::Vector3d &velocity_delta, Eigen::Vector3d &linear_acc_mid) {
  if (index_curr <= index_prev || imu_data_buff_.size() <= index_curr) {
    return false;
  }

  const IMUData &imu_data_curr = imu_data_buff_.at(index_curr);
  const IMUData &imu_data_prev = imu_data_buff_.at(index_prev);

  T = imu_data_curr.time - imu_data_prev.time;

  Eigen::Vector3d linear_acc_curr = Eigen::Vector3d(
      imu_data_curr.linear_acceleration.x, imu_data_curr.linear_acceleration.y,
      imu_data_curr.linear_acceleration.z);
  Eigen::Vector3d  a_curr = GetUnbiasedLinearAcc(linear_acc_curr, R_curr);        //  w系下的a_curr
  Eigen::Vector3d linear_acc_prev = Eigen::Vector3d(
  imu_data_prev.linear_acceleration.x, imu_data_prev.linear_acceleration.y,
  imu_data_prev.linear_acceleration.z);
  Eigen::Vector3d  a_prev = GetUnbiasedLinearAcc(linear_acc_prev, R_prev);        //  w系下的a_prev
  // mid-value acc can improve error state prediction accuracy:
  linear_acc_mid = 0.5 * (a_curr + a_prev);     //  w 系下的linear_acc_mid , 用于更新pos_w 和 vel_w
  velocity_delta = T * linear_acc_mid;
  linear_acc_mid = 0.5 * (linear_acc_curr + linear_acc_prev) - accl_bias_;      //  b 系下的linear_acc_mid

  return true;
}

// 位置解算
void ErrorStateKalmanFilter::UpdatePosition(
    const double &T, const Eigen::Vector3d &velocity_delta) {
  pose_.block<3, 1>(0, 3) += T * vel_ + 0.5 * T * velocity_delta;
  vel_ += velocity_delta;
}
0f0a197c9466661768f2d49047a79a20.png

kalman预测更新,误差值更新

void ErrorStateKalmanFilter::UpdateErrorEstimation(                       //  更新误差值
    const double &T, const Eigen::Vector3d &linear_acc_mid,
    const Eigen::Vector3d &angular_vel_mid) {
  static MatrixF F_1st;
  static MatrixF F_2nd;
  // TODO: update process equation:         //  更新状态方程
  UpdateProcessEquation(linear_acc_mid ,  angular_vel_mid);
  // TODO: get discretized process equations:         //   非线性化
  F_1st  =  F_ *  T;        //  T kalman 周期
  MatrixF   F = MatrixF::Identity()  +   F_1st;
  MatrixB  B =  MatrixB::Zero();
  B.block<3,  3>(kIndexErrorVel,  kIndexNoiseGyro)  =      B_.block<3,  3>(kIndexErrorVel,  kIndexNoiseGyro) * T;
  B.block<3,  3>(kIndexErrorOri,  kIndexNoiseGyro)  =      B_.block<3,  3>(kIndexErrorOri,  kIndexNoiseGyro) *T;
  if(COV.PROCESS.BIAS_FLAG){
      B.block<3,  3>(kIndexErrorAccel,  kIndexNoiseBiasAccel)  =    B_.block<3,  3>(kIndexErrorAccel,  kIndexNoiseBiasAccel)* sqrt(T);
      B.block<3,  3>(kIndexErrorGyro,  kIndexNoiseBiasGyro)  =      B_.block<3,  3>(kIndexErrorGyro,  kIndexNoiseBiasGyro)* sqrt(T);
  }

  // TODO: perform Kalman prediction
  X_ =  F * X_;
  P_ =  F * P_ * F.transpose()   +  B * Q_ * B.transpose();             //   只有方差进行了计算
}
bb90e924602dd3f100e7689fd38aba83.png

根据是否有观测,来更新后验估计

void ErrorStateKalmanFilter::CorrectErrorEstimation(
    const MeasurementType &measurement_type, const Measurement &measurement) {
  //
  // TODO: understand ESKF correct workflow
  //
  Eigen::VectorXd Y;
  Eigen::MatrixXd G, K;
  switch (measurement_type) {
  case MeasurementType::POSE:
    CorrectErrorEstimationPose(measurement.T_nb, Y, G, K);
    break;
  default:
    break;
  }

  // TODO: perform Kalman correct:
  P_ = (MatrixP::Identity() -  K*G)  *  P_ ;          //  后验方差
  X_ =  X_ +  K * (Y - G*X_);                        //  更新后的状态量
}
36242c13f8cdd8df7ae824c782482edc.png

当有观测时:依据下面公式

f202f1d8e3adf859ae3f8c20bb352267.png

代码对应

/**
 * @brief  correct error estimation using pose measurement
 * @param  T_nb, input pose measurement
 * @return void
 */
void ErrorStateKalmanFilter::CorrectErrorEstimationPose(                    //  计算  Y ,G  ,K
    const Eigen::Matrix4d &T_nb, Eigen::VectorXd &Y, Eigen::MatrixXd &G,
    Eigen::MatrixXd &K) {
  //
  // TODO: set measurement:      计算观测 delta pos  、 delta  ori
  //
  Eigen::Vector3d  dp  =  pose_.block<3,  1>(0,  3)  -   T_nb.block<3,  1>(0,  3);
  Eigen::Matrix3d  dR  =  T_nb.block<3,  3>(0, 0).transpose() *  pose_.block<3, 3>(0, 0) ;
  // TODO: set measurement equation:
  Eigen::Vector3d  dtheta  =  Sophus::SO3d::vee(dR  -  Eigen::Matrix3d::Identity() );
  YPose_.block<3, 1>(0, 0)  =  dp;          //    delta  position 
  YPose_.block<3, 1>(3, 0)  =  dtheta;          //   失准角
  Y = YPose_;
  //   set measurement  G
  GPose_.setZero();
  GPose_.block<3, 3>(0, kIndexErrorPos)  =  Eigen::Matrix3d::Identity();
  GPose_.block<3 ,3>(3, kIndexErrorOri)   =  Eigen::Matrix3d::Identity();        
  G  =   GPose_;     
  //   set measurement  C
  CPose_.setZero();
  CPose_.block<3, 3>(0,kIndexNoiseAccel)   =  Eigen::Matrix3d::Identity();
  CPose_.block<3, 3>(3,kIndexNoiseGyro)    =  Eigen::Matrix3d::Identity();
  Eigen::MatrixXd  C  =   CPose_;
  // TODO: set Kalman gain:
  Eigen::MatrixXd R = RPose_;    //  观测噪声
  K =  P_  *  G.transpose() * ( G  *  P_  *  G.transpose( )  +  C * RPose_*  C.transpose() ).inverse() ;
}
c768268e1ea4402a931c0798bf8f552d.png

对应代码

void ErrorStateKalmanFilter::EliminateError(void) {
  //      误差状态量  X_  :   15*1
  // TODO: correct state estimation using the state of ESKF
  //
  // a. position:
  // do it!
  pose_.block<3, 1>(0, 3)  -=  X_.block<3, 1>(kIndexErrorPos, 0 );   //  减去error
  // b. velocity:
  // do it!
  vel_ -=  X_.block<3,1>(kIndexErrorVel, 0 );         
  // c. orientation:
  // do it!
  Eigen::Matrix3d   dtheta_cross =  Sophus::SO3d::hat(X_.block<3,1>(kIndexErrorOri, 0));         //   失准角的反对称矩阵
  pose_.block<3, 3>(0, 0) =  pose_.block<3, 3>(0, 0) * (Eigen::Matrix3d::Identity() - dtheta_cross);     
  Eigen::Quaterniond  q_tmp(pose_.block<3, 3>(0, 0) );
  q_tmp.normalize();        //  为了保证旋转矩阵是正定的
  pose_.block<3, 3>(0, 0) = q_tmp.toRotationMatrix();  

  // d. gyro bias:
  if (IsCovStable(kIndexErrorGyro)) {
    gyro_bias_ -= X_.block<3, 1>(kIndexErrorGyro, 0);           //  判断gyro_bias_error是否可观
  }

  // e. accel bias:
  if (IsCovStable(kIndexErrorAccel)) {
    accl_bias_ -= X_.block<3, 1>(kIndexErrorAccel, 0);          //   判断accel_bias_error是否可观 
  }
}
5e84abd6909eb6ef29c2411d17212721.png
void ErrorStateKalmanFilter::ResetState(void) {
  // reset current state:
  X_ = VectorX::Zero();
}
b2a2ebf0db3c307461756c6974f37731.png 文章仅用于学术分享,如有侵权请联系删除

  

好消息!

小白学视觉知识星球

开始面向外开放啦👇👇👇


  

4124d592e402c0a5e3c1d1679a67bdc0.jpeg

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。


下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。


下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。


交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多传感器融合定位:基于滤波的融合方法 的相关文章

  • PX4 ulg文件格式转化(windows下)

    福利领取 在经过多次尝试ubuntu下安装pyulog失败后 xff0c 多次失败 xff0c 查找相关资料 xff0c 发现是python相关包出现了问题 xff0c 最后发现了anaconda这个好东西 xff0c 包含了python下
  • PX4固定翼姿态控制器详细介绍(一)

    代码版本1 8 2 源码地址 Firmware1 8 2 一 前言 最近需要做一下固定翼的相关姿态控制 xff0c 只对控制流程进行简单介绍 xff0c 特此记录下相关流程 xff0c 方便自己后续进一步调试 xff0c 以下对PX4固定翼
  • Github仓库命名规范

    Github仓库命名规范 命名规则 GIT库名一律采用项目名 类型 年月的形式 其中对项目名的规范如下 xff1a 库名中不得出现下述规定的字符 64 amp 39 39 xff0c lt gt 库名应尽量避免使用 名 名的形式 库名应尽量
  • CVTE嵌入式面经

    2021提前批嵌入式实习 CVTE笔试 xff1a 大约20个选择题和两道手撕代码题 选择题主要是问LINUX一些指令和一些单片机的相关知识 比如中断任务里面该写什么代码之类的 CVTE一面 xff1a 大约半个小时 1 自我介绍 2 谈谈
  • 97条架构师必须掌握的知识

    1 Don 39 t put your resume ahead ofthe requirements by Nitin Borwankar 需求先于履历 身为架构 师要平衡客户 公司和个人的利益 用时兴的技术 为个人履历增光添彩固然重要
  • 以Crotex M3为例讲解stm32芯片内部原理

    一款STM32F103ZET6是72Mhz 64kRAM 512kROM为例进行简要分析其MCU工作原理 1 分清几个概念 1 1RAM可读写静态储存器 平常所说的DDR就是RAM的一种 用于CPU直接交换数据 1 2ROM只可读静态存储器
  • 内外网共用操作

    1 首先将内网 外网的两根网线接入交换机 xff0c 再从交换机出来一根线接入你的电脑 xff08 如果是路由器的话 xff0c 内网 外网的网线接入LAN口 xff0c 再从LAN口出来一根线接入你的电脑 xff09 2 打开IP设置 x
  • 【从零学习OpenCV 4】了解OpenCV的模块架构

    本文首发于 小白学视觉 微信公众号 xff0c 欢迎关注公众号 本文作者为小白 xff0c 版权归人民邮电出版社所有 xff0c 禁止转载 xff0c 侵权必究 xff01 经过几个月的努力 xff0c 小白终于完成了市面上第一本OpenC
  • 对象检测和图像分割有什么区别?

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 01 人工智能中的图像预处理 对象检测和图像分割是计算机视觉的两种方法 xff0c 这两种处理手段在人工智能领域内相当常见 xff0c
  • 基于OpenCV的网络实时视频流传输

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 很多小伙伴都不会在家里或者办公室安装网络摄像头或监视摄像头 但是有时 xff0c 大家又希望能够随时随地观看视频直播 大多数人会选择使
  • 英伟达 GPU显卡计算能力查询表

    近期小白因为项目需要开始在电脑上配置深度学习环境 经过一些列的苦难折磨之后 xff0c 电脑环境终于配置好了 xff0c 但是却被我的显卡劝退了 我是用的是算力2 1的显卡 xff0c 环境要求算力3以上的显卡 xff0c 无奈最后只能使用
  • 一文看懂激光雷达

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 来源 xff1a 摘自中信证券 与雷达工作原理类似 xff0c 激光雷达通过测量激光信号的时间差和相位差来确定距离 xff0c 但其最
  • 传统CV和深度学习方法的比较

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 本文转自 xff1a 新机器视觉 摘要 xff1a 深度学习推动了数字图像处理领域的极限 但是 xff0c 这并不是说传统计算机视觉技
  • Opencv实战 | 用摄像头自动化跟踪特定颜色物体

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 本文转自 xff1a 新机器视觉 1 导语 在之前的某个教程里 xff0c 我们探讨了如何控制Pan Tilt Servo设备来安置一
  • 使用OpenCV和TesseractOCR进行车牌检测

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 目录 1 xff09 目的和简介 2 xff09 前言 3 xff09 使用OpenCV和Haar级联进行车牌检测 4 xff09 使
  • GPS(全球定位系统)

    GPS 全球定位系 统 xff0c 是美国国防部为陆 xff0c 海 xff0c 空三军研制的新一代卫星导航定位系统 xff0c 它是以 24 颗人造卫星作为基础 xff0c 全天候地向全球各地用户提供时实的三维定位 三维测速和全球同步时间
  • 单应性矩阵应用-基于特征的图像拼接

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 本文转自 xff1a 深度学习这件小事 前言 前面写了一篇关于单应性矩阵的相关文章 xff0c 结尾说到基于特征的图像拼接跟对象检测中
  • 前沿 | 一文详解自动驾驶激光雷达和摄像头的数据融合方法

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 本文转自 xff1a 计算机视觉联盟 自动驾驶感知模块中传感器融合已经成为了标配 xff0c 只是这里融合的层次有不同 xff0c 可
  • 使用 YOLO 进行目标检测

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 自从世界了解人工智能以来 xff0c 有一个特别的用例已经被讨论了很多 它们是自动驾驶汽车 我们经常在科幻电影中听到 读到甚至看到这些
  • 概述 | 全景图像拼接技术全解析

    点 击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 前言 图像 视频拼接的主要目的是为了解决相机视野 xff08 FOV Field Of View xff09 限制 xff0c 生成

随机推荐

  • 我靠这份无人机完全指南吹了一整年牛!

    对于多数无人机爱好者来说 xff0c 能自己从头开始组装一台无人机 xff0c 之后加入AI算法 xff0c 能够航拍 xff0c 可以进行目标跟踪 xff0c 是每个人心中的梦想 亲自从零开始完成复杂系统 xff0c 这是掌握核心技术的必
  • 奇异值分解(SVD)原理总结

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 前言 奇异值分解 xff08 SVD xff09 在降维 xff0c 数据压缩 xff0c 推荐系统等有广泛的应用 xff0c 任何矩
  • 用Python实现神经网络(附完整代码)!

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 在学习神经网络之前 xff0c 我们需要对神经网络底层先做一个基本的了解 我们将在本节介绍感知机 反向传播算法以及多种梯度下降法以给大
  • 一文图解卡尔曼滤波(Kalman Filter)

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 译者注 xff1a 这恐怕是全网有关卡尔曼滤波最简单易懂的解释 xff0c 如果你认真的读完本文 xff0c 你将对卡尔曼滤波有一个更
  • 计算机视觉方法概述

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 一 资源简介 今天给大家推荐一份最新的计算机视觉方法概述 xff0c 这份综述详细的讲述了当前计算机视觉领域中各种机器学习 xff0c
  • 通俗易懂的YOLO系列(从V1到V5)模型解读!

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 0 前言 本文目的是用尽量浅显易懂的语言让零基础小白能够理解什么是YOLO系列模型 xff0c 以及他们的设计思想和改进思路分别是什么
  • PWM电流源型逆变器

    nbsp nbsp nbsp nbsp 随着科学技术和生产力的发展 各种结构型式和各种控制方法的逆变器相继问世 而就逆变器而言 不管输出要求恒频恒压还是变频变压 有效消除或降低输出谐波是基本要求 因而逆变电源的谐波抑制一直是研究者致力于解决
  • 下划线在 Python 中的特殊含义

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 Python 中的下划线 下划线在 Python 中是有特殊含义的 xff0c 它们在 Python 的不同地方使用 下面是 Pyth
  • UFA-FUSE:一种用于多聚焦图像融合的新型深度监督混合模型

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 小白导读 论文是学术研究的精华和未来发展的明灯 小白决心每天为大家带来经典或者最新论文的解读和分享 xff0c 旨在帮助各位读者快速了
  • 实战 | 如何制作一个SLAM轨迹真值获取装置?

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 本文知乎作者杨小东授权转载 xff0c 未经授权禁止二次转载 原文 xff1a https zhuanlan zhihu com p
  • 通俗易懂理解朴素贝叶斯分类的拉普拉斯平滑

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 这个男生的四个特征是长相不帅 xff0c 性格不好 xff0c 身高矮 xff0c 不上进 xff0c 我们最终得出的结论是女生不嫁
  • 综述 | 激光与视觉融合SLAM

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 SLAM包含了两个主要的任务 xff1a 定位与构图 xff0c 在移动机器人或者自动驾驶中 xff0c 这是一个十分重要的问题 xf
  • KITTI数据集简介与使用

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 摘要 xff1a 本文融合了Are we ready for Autonomous Driving The KITTI Vision
  • DBSCAN聚类算法原理总结

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 DBSCAN是基于密度空间的聚类算法 xff0c 在机器学习和数据挖掘领域有广泛的应用 xff0c 其聚类原理通俗点讲是每个簇类的密度
  • 深度学习GPU最全对比,到底谁才是性价比之王?

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 本文转自AI新媒体量子位 xff08 公众号 ID QbitAI xff09 搞AI xff0c 谁又没有 GPU之惑 xff1f 张
  • 使用卡尔曼滤波器进行对象跟踪时最容易遗漏什么

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 介绍 卡尔曼滤波器是一种复杂的算法 xff0c 在大多数情况下 xff0c 我们在没有完全理解其方程的情况下使用它 当我开始使用卡尔曼
  • 10分钟掌握异常检测

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 异常检测 也称为离群点检测 是检测异常实例的任务 xff0c 异常实例与常规实例非常不同 这些实例称为异常或离群值 xff0c 而正常
  • 根据图像目标深度测试距离

    clc clear close all warning off addpath 39 func 39 计算物体的深度距离 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • SLAM基础环境配置

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 转自知乎作者 xff1a 佳浩 原文链接 xff1a https zhuanlan zhihu com p 385255026 如今
  • 多传感器融合定位:基于滤波的融合方法

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 SLAM 后端的优化方式大体分为滤波和优化 近些年优化越来越成为主流 xff0c 在学习优化之前 xff0c 掌握滤波的工作原理也十分