当前位置:   article > 正文

拆解KinectFusion算法之TSDF_tsdf fusion

tsdf fusion

TSDF的全称是truncated signed distance function,这个算法的主要功能是为了融合(fusion)相机新观测到的深度信息或者说几何信息,当然也可以融合颜色信息甚至是其他的信息比如法向量和材质等等,总的来讲就是把时序上不断观测到的信息加权平均。

首先,要定义一个体素块的集合,这个体素就类比像素,体素是三维空间中承载一些数量值的最小单元。比如说每个体素块的尺寸选择为4mm,这里假定体素块是立方体,当然也可以是小长方体,另外假定每个坐标轴方向都是256个体素块,那么所有体素块就构成一个1.024m的大立方体。之所以选择256这样的数值是为了方便CUDA加速,一般是32的整数倍,32是一个Warp里面的线程数。常见的体素的维度有128,256,512,具体要看下显卡的显存能支持多大。

接下来我们还是从一段CPU代码来具体了解下TSDF算法的执行过程,实际上一个256x256x256的TSDF融合在CUDA加速下可能不到1ms就算完了,CPU代码写个三重的for循环大概可能是秒级算完,不做realtime应用也还可以接受。这段tsdf的代码同样是参考自Intrinsic3D,稍有改动。

for(int z = 0; z < grid_dim; z++){
    for(int y = 0; y < grid_dim; y++){
        for(int x = 0; x < grid_dim; x++){
            int idx = z * grid_dim * grid_dim + y * grid_dim + x;
            Vec3f pos_world(x * voxel_size, y * voxel_size, z * voxel_size);
            //这里的grid_pose实际上是一个平移,就是把位于第一象限的体素栅格平移到第一帧相机的坐标系下。
            //具体地是分别沿x轴和y轴负向移动一段距离,一般就选择0.5 * grid_dim * voxel_size就可以。
            //另外向z轴正向移动一点距离,这个距离具体看你重建的场景在相机z轴正向的距离,以保证大部分场景可以落到体素栅格内部即可。
            pos_world = grid_pose.topLeftCorner(3, 3) * pos_world + grid_pose.topRightCorner(3, 1);
			//这里选择第一帧相机的坐标系为世界坐标系,world_to_cam是把世界坐标系变换到当前相机世界坐标系的刚体变换。
			//这个刚体变换用ICP进行求解得到。
            Vec3f p = world_to_cam.topLeftCorner(3, 3) * pos_world + world_to_cam.topRightCorner(3, 1);
            
            if(p[2] < 0.0f)
                continue;
			//变换到当前相机坐标系下的体素块根据相机内参进行投影;
            int u = (p[0] / p[2]) * fx + cx + 0.5f;
            int v = (p[1] / p[2]) * fy + cy + 0.5f;
            
            //投出图像范围的体素块不更新
            if(u < 0 || v < 0 || u >= depth_imgae.cols || v >= depth_imgae.rows)
                continue;
            
            const float d = depth_imgae.at<float>(v, u);
            if (d <= 0.0f)
                continue;

            // compute signed distance; positive in front of the observation
            const float sdf = d - p[2];
			
			//体素块相比相机观测到的深度值更靠近相机,sdf是正的,否则就是负的
            if (sdf <= -truncation)
                continue;
            if (sdf >= truncation)
                continue;
            valid_voxel_num++;
            
            const float tsdf = sdf >= 0.0f ? std::min(truncation, sdf) : std::max(-truncation, sdf);

            float weight_update = 1.0f;
           
            // update sdf
            const float w_old = grid_weight[idx];
            const float w_new = w_old + weight_update;
            grid_tsdf[idx] = (grid_tsdf[idx] * w_old + tsdf * weight_update) / w_new;
            // update weight
            grid_weight[idx] = w_new;
        }
    }
}
  • 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

TSDF就写这么多,下一节写MarchingCubes算法。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/376813
推荐阅读
相关标签
  

闽ICP备14008679号