ProjectiveIntegrator
클래스는 3D 맵을 업데이트하는 데 사용ProjectiveIntegrator::ProjectiveIntegrator
생성자interpolator_(config::create<ProjectionInterpolator>(config.interp_method))
:interpolator_
는 ProjectionInterpolator
객체로, config.interp_method
에 따라 생성됩니다. (기본값: adaptive)semantic_integrator_(config.semantic_integrator.create())
:semantic_integrator_
는 semantic_integrator
객체를 설정값에 따라 생성ProjectiveIntegrator::updateMap
함수VolumetricMap
)을 업데이트하는 역할을 하며, InputData
)를 기반으로 TSDF(Truncated Signed Distance Function) 및 기타 정보를 갱신const InputData& data
: 입력 데이터로, 3D 맵을 업데이트하기 위한 센서 정보 및 이미지 데이터를 포함VolumetricMap& map
: 갱신될 3D 맵bool allocate_blocks
: (기본값 True)true
이면, 새로운 블록(데이터 블록)을 생성해 TSDF 맵에 추가auto& tsdf = map.getTsdfLayer();
:
블록 할당 (센서의 가시 범위 내 블록 찾기):
const auto body_T_sensor = data.getSensorPose().cast<float>();
const auto block_indices = findBlocksInViewFrustum(
data.getSensor(), body_T_sensor, map.blockSize(), data.min_range, data.max_range);
body_T_sensor
: 센서의 좌표 변환 행렬을 얻습니다. 이를 통해 센서의 위치와 방향을 결정합니다.findBlocksInViewFrustum
: 주어진 센서의 위치와 시야를 기준으로, 해당 시야 내에 포함되는 3D 맵의 블록(공간적 단위)을 찾습니다. block_indices
는 이러한 블록들의 인덱스를 저장합니다.새로운 블록 할당:
BlockIndices new_blocks;
if (allocate_blocks) {
new_blocks = map.allocateBlocks(block_indices);
}
allocate_blocks == true
), 해당 블록들을 3D 맵에 할당합니다. new_blocks
에 저장됩니다.블록 업데이트:
updateBlocks(block_indices, data, map);
업데이트되지 않은 블록 제거:
for (const auto& idx : new_blocks) {
if (!tsdf.getBlock(idx).updated) {
map.removeBlock(idx);
}
}
updateBlocks
함수는 updateBlock
함수updateBlock
함수block_index
)의 모든 복셀을 업데이트BlockTuple blocks = map.getBlock(block_index);
:
block_index
에 해당하는 블록을 가져옵니다. 복셀 업데이트 준비:
const auto sensor_T_body = data.getSensorPose().cast<float>().inverse();
sensor_T_body
는 센서가 측정한 데이터의 좌표 변환 행렬입니다. 이를 통해 복셀의 좌표를 센서의 좌표계로 변환할 수 있습니다.복셀 업데이트 루프:
for (size_t i = 0; i < blocks.tsdf->numVoxels(); ++i) {
const auto p_sensor = sensor_T_body * blocks.tsdf->getVoxelPosition(i);
const auto measurement = getVoxelMeasurement(p_sensor, data, truncation_distance, voxel_size);
if (!measurement.valid) {
continue;
}
auto voxels = blocks.getVoxels(i);
updateVoxel(data, measurement, truncation_distance, voxels);
was_updated = true;
}
blocks.tsdf->numVoxels()
는 해당 블록 내에 있는 복셀의 개수를 반환하며, 각 복셀의 좌표는 blocks.tsdf->getVoxelPosition(i)
를 통해 얻습니다.sensor_T_body * blocks.tsdf->getVoxelPosition(i)
는 복셀의 좌표를 센서 좌표계로 변환합니다. 이렇게 변환된 좌표는 센서가 바라보는 방향에 맞추어 계산됩니다.getVoxelMeasurement
함수는 해당 복셀에 대한 SDF(서피스와의 거리)를 계산하고, 그 값이 유효한지 여부를 판단합니다.updateVoxel
함수가 해당 복셀의 값을 갱신합니다. 이 함수는 TSDF 및 색상, 의미론적 데이터를 갱신합니다.was_updated
플래그: 복셀이 업데이트되면 was_updated
가 true
로 설정됩니다. 이는 해당 블록이 적어도 한 번은 업데이트되었음을 의미합니다.블록 업데이트 플래그 설정:
if (was_updated) {
blocks.tsdf->setUpdated();
}
updateVoxel
함수는 특정 복셀(voxel)의 데이터를 -> 센서로부터 받은 새로운 측정값에 기반하여 갱신auto& tsdf_voxel = *voxels.tsdf;
const auto prev_weight = tsdf_voxel.weight;
tsdf_voxel.weight =
std::min(tsdf_voxel.weight + measurement.weight, config.max_weight);
tsdf_voxel
: 이 복셀의 TSDF 데이터를 가리킵니다.prev_weight
: 이 복셀의 기존 가중치(weight)입니다. TSDF 값은 여러 센서 측정값이 융합되기 때문에, 각 측정값에 가중치가 부여됩니다.measurement.weight
)을 기존 가중치에 더하여 복셀의 가중치를 갱신합니다. config.max_weight
를 넘지 않도록 제한합니다. (10000)tsdf_voxel.distance =
(tsdf_voxel.distance * prev_weight + measurement.sdf * measurement.weight) /
(prev_weight + measurement.weight);
tsdf_voxel.distance
)에 기존 가중치(prev_weight
)를 곱하고,measurement.sdf
)에 새 가중치(measurement.weight
)를 곱한 후,if (voxels.tracking) {
voxels.tracking->last_observed = data.timestamp_ns;
}
tracking
)가 있다면, 해당 복셀이 마지막으로 관측된 시간을 현재 데이터의 타임스탬프(data.timestamp_ns
)로 갱신합니다. if (measurement.sdf >= truncation_distance) {
return;
}
measurement.sdf
: 해당 복셀이 표면에서 얼마나 떨어져 있는지 나타내는 값입니다.truncation_distance
이상이라면, 복셀이 표면에서 너무 멀리 떨어져 있기 때문에 다른 데이터(예: 색상, 의미론적 정보)를 갱신할 필요가 없습니다. 이 경우 함수는 종료됩니다.if (!data.color_image.empty()) {
const auto color = interpolator_->interpolateColor(
data.color_image, measurement.interpolation_weights);
const float ratio = measurement.weight / (tsdf_voxel.weight + measurement.weight);
tsdf_voxel.color.merge(color, ratio);
}
data.color_image
)에 색상 정보가 포함되어 있다면, 해당 색상 데이터를 복셀의 TSDF에 통합interpolation_weights
는 복셀의 위치를 기반으로 주변 색상 값을 참조하는 가중치measurement.weight
)에 기반한 비율(ratio
)을 계산하고 이를 색상에 반영합니다.if (!semantic_integrator_ || !voxels.semantic) {
return;
}
if (semantic_integrator_->isValidLabel(measurement.label)) {
semantic_integrator_->updateLikelihoods(measurement.label, *voxels.semantic);
}
measurement.label
이 유효한 레이블인지 확인합니다.semantic_integrator_
는 해당 복셀의 의미론적 레이블을 갱신합니다. float ProjectiveIntegrator::computeSDF(const InputData& data, const InterpolationWeights& weights, const float truncation_distance, const float distance_to_voxel) const;
SDF는 센서로부터 voxel까지의 거리를 측정하여 표면과의 거리를 계산합니다. 이때 SDF 값은 표면에서의 거리 차이로 정의됩니다:
이를 통해 해당 voxel이 표면에 가까운지 또는 표면 외부에 있는지를 결정하게 됩니다.
float ProjectiveIntegrator::computeWeight(const Sensor& sensor, const Point& p_C, const float sdf, const float truncation_distance, const float voxel_size) const;