本文为拆解LIO-SAM代码的第二部分。 这部分来分析的是feature
extraction的代码。这部分的内容与A-LOAM中的思路是基本一致的。衡量一个点的平滑程度时,LIO-SAM直接使用range
image来找到邻近点,与A-LOAM中的做法会更高效,但是思想上也差不太多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void calculateSmoothness() { int cloudSize = extractedCloud->points.size(); for (int i = 5; i < cloudSize - 5; i++) { float diffRange = cloudInfo.pointRange[i-5] + cloudInfo.pointRange[i-4] + cloudInfo.pointRange[i-3] + cloudInfo.pointRange[i-2] + cloudInfo.pointRange[i-1] - cloudInfo.pointRange[i] * 10 + cloudInfo.pointRange[i+1] + cloudInfo.pointRange[i+2] + cloudInfo.pointRange[i+3] + cloudInfo.pointRange[i+4] + cloudInfo.pointRange[i+5];
cloudCurvature[i] = diffRange*diffRange;
cloudNeighborPicked[i] = 0; cloudLabel[i] = 0; cloudSmoothness[i].value = cloudCurvature[i]; cloudSmoothness[i].ind = i; } }
|
但是A-LOAM在具体实现的时候,并没有对occluded points以及parallel beam
points点进行去除(虽然在原版的论文中是有提到的),在lio-sam中实现了这一步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| void markOccludedPoints() { int cloudSize = extractedCloud->points.size(); for (int i = 5; i < cloudSize - 6; ++i) { float depth1 = cloudInfo.pointRange[i]; float depth2 = cloudInfo.pointRange[i+1]; int columnDiff = std::abs(int(cloudInfo.pointColInd[i+1] - cloudInfo.pointColInd[i]));
if (columnDiff < 10){ if (depth1 - depth2 > 0.3){ cloudNeighborPicked[i - 5] = 1; cloudNeighborPicked[i - 4] = 1; cloudNeighborPicked[i - 3] = 1; cloudNeighborPicked[i - 2] = 1; cloudNeighborPicked[i - 1] = 1; cloudNeighborPicked[i] = 1; }else if (depth2 - depth1 > 0.3){ cloudNeighborPicked[i + 1] = 1; cloudNeighborPicked[i + 2] = 1; cloudNeighborPicked[i + 3] = 1; cloudNeighborPicked[i + 4] = 1; cloudNeighborPicked[i + 5] = 1; cloudNeighborPicked[i + 6] = 1; } } float diff1 = std::abs(float(cloudInfo.pointRange[i-1] - cloudInfo.pointRange[i])); float diff2 = std::abs(float(cloudInfo.pointRange[i+1] - cloudInfo.pointRange[i]));
if (diff1 > 0.02 * cloudInfo.pointRange[i] && diff2 > 0.02 * cloudInfo.pointRange[i]) cloudNeighborPicked[i] = 1; } }
|
- 去除occluded
points的思想是,对于雷达先后扫描的两个点,如果这两个点扫描的间隔不远,且前后两个点相差的距离很大,那么很有可能在下一帧这些点就会相互遮挡。因为不知道雷达的具体运动状态,所以我们不清楚应该屏蔽哪个方向的。所以这里采取的方法很简单,就是都屏蔽掉,只要先扫描的点的距离远大于后扫描的点的距离,那么先扫描的点的附近点就可能被遮挡,只要先扫描的点的距离远小于后扫描的点的距离,那么后扫描的点的附近点就可能被遮挡。
- 去除parallel beam
points的思想是,如果这一点两侧的点,与该点的距离都很大,那么可以认为这个点在一个近乎平行于发射方向的平面上(也可能是其他情况,比如一个尖角,但是这样的尖角被雷达扫描到的概率是非常小的),我们排除掉这样的点来作特征点。
接下来的提取特征部分,代码与A-LOAM是基本上差不多的,就不多赘述了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| void extractFeatures() { cornerCloud->clear(); surfaceCloud->clear();
pcl::PointCloud<PointType>::Ptr surfaceCloudScan(new pcl::PointCloud<PointType>()); pcl::PointCloud<PointType>::Ptr surfaceCloudScanDS(new pcl::PointCloud<PointType>());
for (int i = 0; i < N_SCAN; i++) { surfaceCloudScan->clear();
for (int j = 0; j < 6; j++) {
int sp = (cloudInfo.startRingIndex[i] * (6 - j) + cloudInfo.endRingIndex[i] * j) / 6; int ep = (cloudInfo.startRingIndex[i] * (5 - j) + cloudInfo.endRingIndex[i] * (j + 1)) / 6 - 1;
if (sp >= ep) continue;
std::sort(cloudSmoothness.begin()+sp, cloudSmoothness.begin()+ep, by_value());
int largestPickedNum = 0; for (int k = ep; k >= sp; k--) { int ind = cloudSmoothness[k].ind; if (cloudNeighborPicked[ind] == 0 && cloudCurvature[ind] > edgeThreshold) { largestPickedNum++; if (largestPickedNum <= 20){ cloudLabel[ind] = 1; cornerCloud->push_back(extractedCloud->points[ind]); } else { break; }
cloudNeighborPicked[ind] = 1; for (int l = 1; l <= 5; l++) { int columnDiff = std::abs(int(cloudInfo.pointColInd[ind + l] - cloudInfo.pointColInd[ind + l - 1])); if (columnDiff > 10) break; cloudNeighborPicked[ind + l] = 1; } for (int l = -1; l >= -5; l--) { int columnDiff = std::abs(int(cloudInfo.pointColInd[ind + l] - cloudInfo.pointColInd[ind + l + 1])); if (columnDiff > 10) break; cloudNeighborPicked[ind + l] = 1; } } }
for (int k = sp; k <= ep; k++) { int ind = cloudSmoothness[k].ind; if (cloudNeighborPicked[ind] == 0 && cloudCurvature[ind] < surfThreshold) {
cloudLabel[ind] = -1; cloudNeighborPicked[ind] = 1;
for (int l = 1; l <= 5; l++) {
int columnDiff = std::abs(int(cloudInfo.pointColInd[ind + l] - cloudInfo.pointColInd[ind + l - 1])); if (columnDiff > 10) break;
cloudNeighborPicked[ind + l] = 1; } for (int l = -1; l >= -5; l--) {
int columnDiff = std::abs(int(cloudInfo.pointColInd[ind + l] - cloudInfo.pointColInd[ind + l + 1])); if (columnDiff > 10) break;
cloudNeighborPicked[ind + l] = 1; } } }
for (int k = sp; k <= ep; k++) { if (cloudLabel[k] <= 0){ surfaceCloudScan->push_back(extractedCloud->points[k]); } } }
surfaceCloudScanDS->clear(); downSizeFilter.setInputCloud(surfaceCloudScan); downSizeFilter.filter(*surfaceCloudScanDS);
*surfaceCloud += *surfaceCloudScanDS; } }
|
之后将提取的特征点发布出去,feature extraction的部分就结束了。