激光閉環檢測Scancontext閱讀筆記


@


Scan Context: Egocentric Spatial Descriptor for Place Recognition within 3D Point Cloud Map(IROS2018)
在這里插入圖片描述

一、構建Scan Context

在這里插入圖片描述\(N_r\):ring分成多少份
\(N_s\): sectors分成多少份
在這里插入圖片描述在這里插入圖片描述

// 制作Scancontext
MatrixXd SCManager::makeScancontext( pcl::PointCloud<SCPointType> & _scan_down )
{
    TicToc t_making_desc;

    int num_pts_scan_down = _scan_down.points.size();

    // main
    // 初始化desc=Scancontext
    const int NO_POINT = -1000;
    MatrixXd desc = NO_POINT * MatrixXd::Ones(PC_NUM_RING, PC_NUM_SECTOR);

    SCPointType pt;
    float azim_angle, azim_range; // 極坐標wihtin 2d plane
    int ring_idx, sctor_idx; //Scancontext中的索引,注意是從1開始的
    for (int pt_idx = 0; pt_idx < num_pts_scan_down; pt_idx++)
    {
        pt.x = _scan_down.points[pt_idx].x; 
        pt.y = _scan_down.points[pt_idx].y;
        pt.z = _scan_down.points[pt_idx].z + LIDAR_HEIGHT; // naive adding is ok (all points should be > 0).

        // xyz to ring, sector
        azim_range = sqrt(pt.x * pt.x + pt.y * pt.y);
        azim_angle = xy2theta(pt.x, pt.y);

        // if range is out of roi, pass
        // 超出范圍的去掉
        if( azim_range > PC_MAX_RADIUS )
            continue;

        ring_idx = std::max( std::min( PC_NUM_RING, int(ceil( (azim_range / PC_MAX_RADIUS) * PC_NUM_RING )) ), 1 );
        sctor_idx = std::max( std::min( PC_NUM_SECTOR, int(ceil( (azim_angle / 360.0) * PC_NUM_SECTOR )) ), 1 );

        // taking maximum z 
        // 獲取每個bin中的z最大值
        if ( desc(ring_idx-1, sctor_idx-1) < pt.z ) // -1 means cpp starts from 0
            desc(ring_idx-1, sctor_idx-1) = pt.z; // update for taking maximum value at that bin
    }

    // reset no points to zero (for cosine dist later)
    // 沒有點的bin=0
    for ( int row_idx = 0; row_idx < desc.rows(); row_idx++ )
        for ( int col_idx = 0; col_idx < desc.cols(); col_idx++ )
            if( desc(row_idx, col_idx) == NO_POINT )
                desc(row_idx, col_idx) = 0;

    t_making_desc.toc("PolarContext making");

    return desc;
} // SCManager::makeScancontext

二、計算Scan Context的每一行的均值作為RingKey

//Scancontext每一行的均值作為Ringkey
MatrixXd SCManager::makeRingkeyFromScancontext( Eigen::MatrixXd &_desc )
{
    /* 
     * summary: rowwise mean vector
    */
    Eigen::MatrixXd invariant_key(_desc.rows(), 1);
    for ( int row_idx = 0; row_idx < _desc.rows(); row_idx++ )
    {
        Eigen::MatrixXd curr_row = _desc.row(row_idx);
        invariant_key(row_idx, 0) = curr_row.mean();
    }

    return invariant_key;
} // SCManager::makeRingkeyFromScancontext

三、將所有歷史幀的RingKey構建Kd-tree查找候選關鍵幀

四、遍歷候選關鍵幀,選擇距離最近的幀作為匹配幀。

計算距離的步驟

  1. 計算每一幀的Sectorkey
  2. 使用Sectorkey,計算當前幀和閉環幀的偏移量shfit
  3. 使用偏移量對齊兩幀
  4. 計算兩幀的每一列距離的平均值作為總的距離值
    在這里插入圖片描述
  5. 距離最小且滿足閾值的候選關鍵幀即為閉環關鍵幀返回索引id

五、再用icp匹配

優缺點

優點

  1. 速度快
  2. 旋轉不變性

缺點

  1. 只保留z的最大值丟失了信息
  2. 個人認為距離只相差幾米時應該就會導致相似度很低而失效,比如車道很寬,原來靠左現在靠右可能都會失效

打賞

碼字不易,如果對您有幫助,就打賞一下吧O(∩_∩)O

支付寶

微信


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM