Orbeez-SLAM
2023-11-18 23:07:14 0 举报
AI智能生成
对Orbeez-slam代码中orbslam2和instant-ngp结合部分的一个解读
作者其他创作
大纲/内容
- NerfMapping.cu
mpMap->frame();
- System.cu
mpMap = new Map(strSettingsFile, strSlamTransform, bTrainExtrinsicWithPhotometric);// 其中strSlamTransform = "Orbeez-SLAM.json";strSettingPath = argv[2] = configs/RGB-D/Replica/office0.yaml
mpTestbed->load_training_data(strSlamTransform);
//在这里会对一些数据进行加载,主要加载了
images.resize(result.n_images);
result.xforms.resize(result.n_images);
result.metadata.resize(result.n_images);
result.pixelmemory.resize(result.n_images);
result.depthmemory.resize(result.n_images);
result.raymemory.resize(result.n_images);// 这个包括上面的容器大小都为0
result.info.depth_scale
result.camera_distortion.params
result.camera_distortion.mode = ECameraDistortionMode::Iterative;
result.principal_point
result.aabb_scale
result.sharpness_data
//在这里会对一些数据进行加载,主要加载了
images.resize(result.n_images);
result.xforms.resize(result.n_images);
result.metadata.resize(result.n_images);
result.pixelmemory.resize(result.n_images);
result.depthmemory.resize(result.n_images);
result.raymemory.resize(result.n_images);// 这个包括上面的容器大小都为0
result.info.depth_scale
result.camera_distortion.params
result.camera_distortion.mode = ECameraDistortionMode::Iterative;
result.principal_point
result.aabb_scale
result.sharpness_data
mpTestbed->reload_network_from_file(network_config_path);// network_config_path = "./Thirdparty/instant-ngp-kf/configs/nerf/base.json"
m_network_config = load_network_config(m_network_config_path);// 就加载了base.json里的数据
reset_network();
分别创建了3个对象的模型:
1、失真图模型:m_distortion
2、普通训练模型:m
3、贴图(背景)训练模型:m_envmap
1、失真图模型:m_distortion
2、普通训练模型:m
3、贴图(背景)训练模型:m_envmap
mpTestbed->m_train = true;// 这里要求进行训练
mpTestbed->m_nerf.training.optimize_extrinsics = bTrainCameraWithPhotometric;// 是否要将光度误差加入到训练监督中
mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer,mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);// 开启跟踪线程
mptNerfMapping = new thread(&ORBEEZ::NerfMapping::Run, mpNerfMapper);
void NerfMapping::Run()
while(1)
SetAcceptKeyFrames(false);// 首先不再接受关键帧
if(CheckNewKeyFrames())// 若新关键帧非空
ProcessNewKeyFrame();// 处理缓冲队列第一个关键帧
mpCurrentKeyFrame = mlNewKeyFrames.front();// 取出列表中最前面的关键帧,作为当前要处理的关键帧
mlNewKeyFrames.pop_front();// 取出最前面的关键帧后,在原来的列表里删掉该关键帧
mlNewKeyFrames.pop_front();// 取出最前面的关键帧后,在原来的列表里删掉该关键帧
mpCurrentKeyFrame->ComputeBoW();// 计算该关键帧特征点的词袋向量,用于后续特征匹配
for(size_t i=0; i<vpMapPointMatches.size(); i++)// 对当前处理的这个关键帧中的所有的地图点展开遍历
if(!pMP->isBad())
if(!pMP->IsInKeyFrame(mpCurrentKeyFrame))// 如果地图点不是来自当前帧的观测
pMP->AddObservation(mpCurrentKeyFrame, i);// 为当前地图点添加观测
pMP->UpdateNormalAndDepth();// 获得该点的平均观测方向和观测距离范围
pMP->ComputeDistinctiveDescriptors();// 更新地图点的最佳描述子
else// 若地图点来自当前帧的观测(这些地图点可能来自双目或RGBD在创建关键帧中新生成的地图点,或者是CreateNewMapPoints 中通过三角化产生)
mlpRecentAddedMapPoints.push_back(pMP); // 将上述地图点放入mlpRecentAddedMapPoints,等待后续MapPointCulling函数的检验
mpCurrentKeyFrame->UpdateConnections();// 更新关键帧间的连接关系(共视图)
mpMap->AddKeyFrame(mpCurrentKeyFrame);// 将该关键帧插入到地图中
std::tuple<ngp::TrainingXForm*,int> t = mpTestbed->add_training_image(frame_config, img, depth);// 帧配置(frame_config)、图像数据(img)和深度数据(depth)添加到 mpTestbed 中,其中uint16_t *depth = nullptr;应该是没有传入实际的深度图
TrainingXForm* NerfXform = m_nerf.training.dataset.add_training_image(frame, img, depth, alpha, mask);// 这里开始正式加载数据
传入nerf的数据:稀疏点云,rbga图
ngp::TrainingXForm *pXform = std::get<0>(t);
int index = std::get<1>(t);
pKF->SetNerfXformPointer(pXform, index);// mpNerfXform = pXform; mpNerfIndex = index;
MapPointCulling();// 剔除劣质地图点
剔除地图点的规则:
规则1:已经是坏点(pMP->isBad()),直接从队列中剔除
规则2:跟踪到该地图点的帧数相比预计可观测到该地图点的帧数的比例小于25%(跟踪到地图点的帧数太少),把点设置为坏点,直接从队列中剔除
规则3:从该点建立开始,到现在已经过了不小于2个关键帧,同时观测到该点的相机数却不超过阈值cnThObs,把点设置为坏点,直接从队列中剔除
规则4:从建立该点开始,已经过了3个关键帧而没有被剔除,则认为是高质量的点,仅从队列中剔除
CreateNewMapPoints();// 创建新地图点
if(!CheckNewKeyFrames())// 若新关键帧为空
SearchInNeighbors();// 融合当前关键帧和共视关键帧的MaoPoint(融合当前关键帧与相邻关键帧帧(两级相邻)中重复的地图点)
if(!CheckNewKeyFrames() && !stopRequested())// 若新关键帧非空,同时不停止建图
if(mpMap->KeyFramesInMap()>2)// 只要地图中的关键帧数量大于2
Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame, &mbAbortBA, mpMap);// 执行局部BA
原ORB-slam2执行了关键帧剔除的操作,Orbeez-slam没有执行,可能是为了获取更多的点进行nerf重建
KeyFrameCulling()// 如果至少存在三帧的地图点比当前共视关键帧pkf的质量好,会记录这些地图点的数量,只要这个地图点的数量超过了总有效地图点数的90%,就会剔除当前共视关键帧
mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame);// 将当前帧加入到闭环检测队列中
else if(Stop())// 若要终止当前线程,就终止当前线程
mpMap->update_transformsGPU();// 可能将地图点投射到另一个坐标系
mpMap->frame();// 在这里会构建稀疏点云
map_points.push_back(map_point);
ResetIfRequested();// mbResetRequested=false;
SetAcceptKeyFrames(true);// 开始接受关键帧
SetFinish();
- Map.cu
mpTestbed->add_sparse_point_cloud(map_points, ref_map_points);// 用于添加稀疏点云,注意一下m_nerf.sparse_map_points_positions_gpu.data()这个变量
bool value = mpTestbed->frame();// 用稀疏点云拿去NeRF,注意这里的frame()和之前那个不同,这里的是Testbed::frame()
// 其中mpTestbed = std::make_shared<ngp::Testbed>(ngp::ETestbedMode::NerfSlam);
void Testbed::add_sparse_point_cloud(std::vector<Eigen::Vector3f>& sparse_map_points_positions, std::vector<Eigen::Vector3f>& sparse_ref_map_points_positions)// 用于添加稀疏点云
// 其中sparse_map_points_positions = map_points,sparse_ref_map_points_positions = ref_map_points
// 其中sparse_map_points_positions = map_points,sparse_ref_map_points_positions = ref_map_points
m_nerf.sparse_map_points_positions_gpu.resize_and_copy_from_host(m_nerf.sparse_map_points_positions);// 应该是把cpu上的数据迁移到gpu上
m_nerf.sparse_ref_map_points_positions_gpu.resize_and_copy_from_host(m_nerf.sparse_ref_map_points_positions);
// 将稀疏点数据分别存在m_nerf.sparse_map_points_positions_gpu和m_nerf.sparse_ref_map_points_positions_gpu上
m_nerf.sparse_ref_map_points_positions_gpu.resize_and_copy_from_host(m_nerf.sparse_ref_map_points_positions);
// 将稀疏点数据分别存在m_nerf.sparse_map_points_positions_gpu和m_nerf.sparse_ref_map_points_positions_gpu上
m_nerf.sparse_map_points_positions.push_back(m_nerf.training.dataset.slam_point_to_ngp(map_point));// 加点操作,应该是把点放入了m_nerf.training.dataset中,但并没有放入颜色信息
- testbed.cu
bool Testbed::frame(){} //该函数内部用来训练NeRF网络
train_and_render(skip_rendering);// skip_rendering = true
train(m_training_batch_size);// m_training_batch_size = 1<<18,其实就是2^18
if (m_training_step % n_prep_to_skip == 0)
training_prep_nerf(batch_size, m_training_stream);// batch_size = m_training_batch_size, m_training_stream = cudaStream_t m_training_stream;用于生成稠密地图,判断体素网格占据关系
if (m_training_step < 256)
update_density_grid_nerf(alpha, NERF_GRIDSIZE()*NERF_GRIDSIZE()*NERF_GRIDSIZE()*n_cascades, 0, stream);// 加入稠密地图点,并更新体素网格的密度值,其中alpha = 0.95f,中间的参数为128*128*128*(m_nerf.max_cascade+1),stream = m_training_stream
update_density_grid_nerf(float decay, uint32_t n_uniform_density_grid_samples, uint32_t n_nonuniform_density_grid_samples, cudaStream_t stream),对应起来就是,decay = alpha, n_uniform_density_grid_samples = 128*128*128*(m_nerf.max_cascade+1), n_nonuniform_density_grid_samples = 0, stream = m_training_stream
update_density_grid_nerf(float decay, uint32_t n_uniform_density_grid_samples, uint32_t n_nonuniform_density_grid_samples, cudaStream_t stream),对应起来就是,decay = alpha, n_uniform_density_grid_samples = 128*128*128*(m_nerf.max_cascade+1), n_nonuniform_density_grid_samples = 0, stream = m_training_stream
clear_density_grid_sample_ct_msb();// 用于将体素网格中的占据信息全部置0
update_density_grid_sample_ct_sparse_point_cloud(m_nerf.sparse_map_points_positions.size(),// 应该表示的是所有的点云数
m_nerf.sparse_map_points_positions_gpu.data(),// 点云的坐标sparse_map_points_positions_gpu就是从slam构造的地图点拷贝到gpu上的
m_nerf.density_grid_sample_ct.data());// 根据orb-slam2构建的稀疏点云将density_grid_sample_ct 数组中的特定位置的最高有效位设置为1,表示该位置存在点云数据
m_nerf.sparse_map_points_positions_gpu.data(),// 点云的坐标sparse_map_points_positions_gpu就是从slam构造的地图点拷贝到gpu上的
m_nerf.density_grid_sample_ct.data());// 根据orb-slam2构建的稀疏点云将density_grid_sample_ct 数组中的特定位置的最高有效位设置为1,表示该位置存在点云数据
update_density_grid_sample_ct_sparse_point_cloud();// 这个和上面那个一样,只不过是检测的是参考点云中的体素网格是否被占用(ref_map_points)
最终添加的新的地图点是放在m_nerf.nerf_triangulation_map_points_positions中的,会先判断这里面的大小(因为一开始并没有往里面加点,所以数量应该是0),只要没加到300000个点,就会执行下面的操作(if(m_nerf.nerf_triangulation_map_points_positions.size() < 300000))
generate_grid_map_points_nerf_nonuniform();// 满足一定条件则对某个体素网格的计数器进行加1操作,并记录这个网格中的所有点云数据
其中,m_nerf.density_grid_sample_ct.data()这个数据应该是个多位二进制数,某一位表示的是这个体素位置是否存在点云数据density_grid_sample_ct[idx+grid_mip_offset(mip)] |= 0x80;其他位的数据可能包含着点云的坐标啥的,因为要加以区分,其中某一位应该还包含了体素的权重值,后面判断了权重值和阈值128的大小关系
out = map_points_positions 只存储了体素网格中大于一定权值的点云,而这个点云在后续会送去构建稠密点云
其中,m_nerf.density_grid_sample_ct.data()这个数据应该是个多位二进制数,某一位表示的是这个体素位置是否存在点云数据density_grid_sample_ct[idx+grid_mip_offset(mip)] |= 0x80;其他位的数据可能包含着点云的坐标啥的,因为要加以区分,其中某一位应该还包含了体素的权重值,后面判断了权重值和阈值128的大小关系
out = map_points_positions 只存储了体素网格中大于一定权值的点云,而这个点云在后续会送去构建稠密点云
if (map_points_counter_cpu > 0){m_nerf.nerf_triangulation_map_points_positions.insert(m_nerf.nerf_triangulation_map_points_positions.end(), map_points_positions_cpu.begin(), map_points_positions_cpu.end());},文中说cnt的值大于一定数时,就把该体素里的所有点拿去构建稠密地图,没想到这个阈值为0.....
nerf_triangulation_map_points_positions包含了所有的稠密地图点,刚开始应该是什么点都没有的
nerf_triangulation_map_points_positions包含了所有的稠密地图点,刚开始应该是什么点都没有的
generate_grid_samples_nerf_nonuniform();// density_grid_positions存储了相对于边界框aabb的新的点云坐标,同时包含了一个进行了归一化或映射操作后的时间步长
density_grid_indices存储了key的索引
density_grid_indices存储了key的索引
generate_grid_samples_nerf_nonuniform();// NERF_MIN_OPTICAL_THICKNESS() = 0.01f,这个函数和上面那个函数实现的作用是一样的,只是输入的采样点数量不一样,上面是均匀采样的数量,这个是非均匀采样的数量;同时用于保存的点云的容器不一样,indices也不一样
m_nerf_network->density(stream, density_grid_position_matrix, density_matrix, false);// 输入数据进行编码参数训练以及密度网格训练
splat_grid_samples_nerf_max_nearest_neighbor(n_density_grid_samples, density_grid_indices, mlp_out, density_grid_tmp, m_nerf.rgb_activation, m_nerf.density_activation);// 处理密度网格样本并计算密度
tomicMax((uint32_t*)&grid_out[local_idx], __float_as_uint(optical_thickness));// 存储这两个当中较大的值
triangualtion_ema_grid_samples_nerf(n_elements, decay, m_nerf.density_grid_ema_step, m_nerf.density_grid.data(), density_grid_tmp, m_nerf.density_grid_sample_ct.data());// 根据重要性度量和衰减因子更新密度网格m_nerf.density_grid.data()的值,其中grid_out = m_nerf.density_grid.data()
float val = (prev_val<0.f) ? prev_val : fmaxf(prev_val * decay, importance);// fmaxf返回较大的那个数
grid_out[i] = val;
grid_out[i] = val;
update_density_grid_mean_and_bitfield(stream);// 处理密度网格的数据,并最终计算其均值以用于后续处理
else
update_density_grid_nerf(alpha, NERF_GRIDSIZE()*NERF_GRIDSIZE()*NERF_GRIDSIZE()/4*n_cascades, NERF_GRIDSIZE()*NERF_GRIDSIZE()*NERF_GRIDSIZE()/4*n_cascades, stream);
后续分支和上面一致
- 查找叶子优化器并更新其设置
train_nerf(batch_size,get_loss_scalar, m_training_stream);// 其中bool get_loss_scalar = m_training_step % 16 == 0;
train_nerf_step(uint32_t target_batch_size, uint32_t n_rays_per_batch, uint32_t* counter, uint32_t* compacted_counter, float* loss, cudaStream_t stream)
generate_training_samples_nerf// 这一步用于生成训练的样本,即要执行体素跳过策略,着重注意一下m_nerf.training.metadata_gpu这个变量
m_network->inference_mixed_precision(stream, coords_matrix, rgbsigma_matrix, false);// 网络执行混合精度推理,同时确认输入输出的维度是否符合要求
compute_loss_kernel_train_nerf// 计算颜色、深度损失来训练nerf
LossAndGradient lg = loss_and_gradient(rgbtarget, rgb_ray, loss_type);// 返回损失和梯度,rgb_ray就是射线的加权值
LossAndGradient lg_depth = loss_and_gradient(Array3f::Constant(target_depth), Array3f::Constant(depth_ray), depth_loss_type);
update_density_grid_sample_ct
bool train_camera = m_nerf.training.optimize_extrinsics || m_nerf.training.optimize_distortion || m_nerf.training.optimize_focal_length;// train_camera = false;
render_frame(m_smoothed_camera, m_smoothed_camera, Eigen::Vector4f::Zero(), render_buffer);
render_nerf(render_buffer, max_res, focal_length, camera_matrix0, camera_matrix1, nerf_rolling_shutter, screen_center, m_inference_stream);
子主题
- 对const uint32_t i = threadIdx.x + blockIdx.x * blockDim.x;的解释
变量解读
共视图
./build/rgbd_replica Vocabulary/ORBvoc.txt configs/RGB-D/Replica/office0.yaml Replica/office0/
{
"loss": {
"otype": "Huber"
},
"optimizer": {
"otype": "Ema",
"decay": 0.95,
"nested": {
"otype": "ExponentialDecay",
"decay_start": 20000,
"decay_interval": 10000,
"decay_base": 0.33,
"nested": {
"otype": "Adam",
"learning_rate": 1e-2,
"beta1": 0.9,
"beta2": 0.99,
"epsilon": 1e-15,
"l2_reg": 1e-6
}
}
},
"encoding": {
"otype": "HashGrid",
"n_levels": 16,
"n_features_per_level": 2,
"log2_hashmap_size": 19,
"base_resolution": 16
},
"network": {
"otype": "FullyFusedMLP",
"activation": "ReLU",
"output_activation": "None",
"n_neurons": 64,
"n_hidden_layers": 1
},
"dir_encoding": {
"otype": "Composite",
"nested": [
{
"n_dims_to_encode": 3,
"otype": "SphericalHarmonics",
"degree": 4
},
{
"otype": "Identity",
"n_bins": 4,
"degree": 4
}
]
},
"rgb_network": {
"otype": "FullyFusedMLP",
"activation": "ReLU",
"output_activation": "None",
"n_neurons": 64,
"n_hidden_layers": 2
},
"distortion_map": {
"resolution": [32, 32],
"optimizer": {
"otype": "ExponentialDecay",
"decay_start": 10000,
"decay_interval": 5000,
"decay_end": 25000,
"decay_base": 0.33,
"nested": {
"otype": "Adam",
"learning_rate": 1e-4,
"beta1": 0.9,
"beta2": 0.99,
"epsilon": 1e-8
}
}
},
"envmap": {
"loss": {
"otype": "RelativeL2"
},
"optimizer": {
"otype": "Ema",
"decay": 0.99,
"nested": {
"otype": "ExponentialDecay",
"decay_start": 10000,
"decay_interval": 5000,
"decay_base": 0.33,
"nested": {
"otype": "Adam",
"learning_rate": 1e-2,
"beta1": 0.9,
"beta2": 0.99,
"beta3": 0.9,
"beta_shampoo": 0.0,
"epsilon": 1e-10,
"identity": 0.0001,
"cg_on_momentum": false,
"frobenius_normalization": true,
"l2_reg": 1e-10
}
}
}
}
}
"loss": {
"otype": "Huber"
},
"optimizer": {
"otype": "Ema",
"decay": 0.95,
"nested": {
"otype": "ExponentialDecay",
"decay_start": 20000,
"decay_interval": 10000,
"decay_base": 0.33,
"nested": {
"otype": "Adam",
"learning_rate": 1e-2,
"beta1": 0.9,
"beta2": 0.99,
"epsilon": 1e-15,
"l2_reg": 1e-6
}
}
},
"encoding": {
"otype": "HashGrid",
"n_levels": 16,
"n_features_per_level": 2,
"log2_hashmap_size": 19,
"base_resolution": 16
},
"network": {
"otype": "FullyFusedMLP",
"activation": "ReLU",
"output_activation": "None",
"n_neurons": 64,
"n_hidden_layers": 1
},
"dir_encoding": {
"otype": "Composite",
"nested": [
{
"n_dims_to_encode": 3,
"otype": "SphericalHarmonics",
"degree": 4
},
{
"otype": "Identity",
"n_bins": 4,
"degree": 4
}
]
},
"rgb_network": {
"otype": "FullyFusedMLP",
"activation": "ReLU",
"output_activation": "None",
"n_neurons": 64,
"n_hidden_layers": 2
},
"distortion_map": {
"resolution": [32, 32],
"optimizer": {
"otype": "ExponentialDecay",
"decay_start": 10000,
"decay_interval": 5000,
"decay_end": 25000,
"decay_base": 0.33,
"nested": {
"otype": "Adam",
"learning_rate": 1e-4,
"beta1": 0.9,
"beta2": 0.99,
"epsilon": 1e-8
}
}
},
"envmap": {
"loss": {
"otype": "RelativeL2"
},
"optimizer": {
"otype": "Ema",
"decay": 0.99,
"nested": {
"otype": "ExponentialDecay",
"decay_start": 10000,
"decay_interval": 5000,
"decay_base": 0.33,
"nested": {
"otype": "Adam",
"learning_rate": 1e-2,
"beta1": 0.9,
"beta2": 0.99,
"beta3": 0.9,
"beta_shampoo": 0.0,
"epsilon": 1e-10,
"identity": 0.0001,
"cg_on_momentum": false,
"frobenius_normalization": true,
"l2_reg": 1e-10
}
}
}
}
}
收藏
0 条评论
下一页