lio-sam project pointcloud study
投影函数:
//input : laserCloudIn
output :
rangeMat :Matrix size: (rings=N_SCAN)*Horizon_SCAN value:point's distance
fullCloud :PointCloud size: 1*(rings*Horizon_SCAN) value:point self
void projectPointCloud(){int cloudSize = laserCloudIn->points.size();// range image projectionfor (int i = 0; i < cloudSize; ++i){PointType thisPoint;thisPoint.x = laserCloudIn->points[i].x;thisPoint.y = laserCloudIn->points[i].y;thisPoint.z = laserCloudIn->points[i].z;thisPoint.intensity = laserCloudIn->points[i].intensity;float range = pointDistance(thisPoint);if (range < lidarMinRange || range > lidarMaxRange)continue;int rowIdn = laserCloudIn->points[i].ring;if (rowIdn < 0 || rowIdn >= N_SCAN)continue;if (rowIdn % downsampleRate != 0)continue;int columnIdn = -1;if (sensor == SensorType::VELODYNE || sensor == SensorType::OUSTER){float horizonAngle = atan2(thisPoint.x, thisPoint.y) * 180 / M_PI;static float ang_res_x = 360.0/float(Horizon_SCAN);columnIdn = -round((horizonAngle-90.0)/ang_res_x) + Horizon_SCAN/2;if (columnIdn >= Horizon_SCAN)columnIdn -= Horizon_SCAN;}else if (sensor == SensorType::LIVOX){columnIdn = columnIdnCountVec[rowIdn];columnIdnCountVec[rowIdn] += 1;}if (columnIdn < 0 || columnIdn >= Horizon_SCAN)continue;if (rangeMat.at<float>(rowIdn, columnIdn) != FLT_MAX)continue;thisPoint = deskewPoint(&thisPoint, laserCloudIn->points[i].time);rangeMat.at<float>(rowIdn, columnIdn) = range;int index = columnIdn + rowIdn * Horizon_SCAN;fullCloud->points[index] = thisPoint;}}
-round((angle-90)/res) + SCAN/2 实现: 将坐标系旋转90°(使0°对应正前方)1 通过取整和偏移量调整,将角度均匀映射到[0, Horizon_SCAN-1]的索引范围1 ????
该公式实现激光雷达点云的水平角度到列索引的映射,具体原理如下:
一、坐标系旋转90°
-
原始角度定义
atan2(x,y)
计算结果为点相对于Y轴的角度(0°对应正Y轴方向)19
示例:点(1,1)对应45°,点(-1,1)对应-45° -
旋转调整
angle-90
将坐标系顺时针旋转90°,使:- 0°对应正前方(原始Y轴正方向)1
- 90°对应左侧(原始X轴负方向)
- -90°对应右侧(原始X轴正方向)9
二、分辨率归一化
步骤 | 数学表达 | 作用 |
---|---|---|
角度除分辨率 | (angle-90)/res | 将角度值转换为列索引的浮点数形式1 |
四舍五入 | round() | 确保索引为整数1 |
符号反转 | - | 补偿坐标系旋转后的方向反转1 |
三、偏移量调整
+ Horizon_SCAN/2
实现:
- 将[-SCAN/2, SCAN/2]的索引范围平移至[0, Horizon_SCAN-1]1
- 确保正前方(0°)位于图像中心列3
四、典型参数示例
当Horizon_SCAN=1800(0.2°/列)时: - 正前方点(0,1)→angle=0°→columnIdn=900 - 左侧90°点(-1,0)→columnIdn=1350 - 右侧-90°点(1,0)→columnIdn=450
该映射方法广泛应用于Velodyne/Ouster等机械式激光雷达的水平角度分箱处理。
点云提炼函数:提取出有效的点rangeMat.at<float>(i,j) != FLT_MAX,用于特征提取
cloudInfo.start_ring_index[i]= count - 1 + 5
cloudInfo.end_ring_index[i] = count -1 - 5;
需要10个水平附近点来提取特征,因此特征点索引范围[5,end-5]
cloudInfo.point_col_ind[count]:点的列索引,即垂直索引。
void cloudExtraction(){int count = 0;// extract segmented cloud for lidar odometryfor (int i = 0; i < N_SCAN; ++i){cloudInfo.start_ring_index[i] = count - 1 + 5;for (int j = 0; j < Horizon_SCAN; ++j){if (rangeMat.at<float>(i,j) != FLT_MAX){// mark the points' column index for marking occlusion latercloudInfo.point_col_ind[count] = j;// save range infocloudInfo.point_range[count] = rangeMat.at<float>(i,j);// save extracted cloudextractedCloud->push_back(fullCloud->points[j + i*Horizon_SCAN]);// size of extracted cloud++count;}}cloudInfo.end_ring_index[i] = count -1 - 5;}}
垂直索引 is 列索引 or 行索引 ?
垂直索引等同于列索引,与行索引存在本质区别,具体对比如下:
🔍 索引类型定义
索引类型 | 核心特征 | 数据结构 |
---|---|---|
垂直索引(列索引) | 按列(字段)组织存储数据,同列数据连续存放49 | 列式存储(如 Parquet、ClickHouse)49 |
行索引 | 按行(记录)定位数据,存储记录的物理地址28 | 行式存储(如 InnoDB B+树主键 |