三维重建KInectFusion 学习笔记

本文介绍了使用KInectFusion进行实时三维重建的步骤,包括数据集准备、点云计算、内存管理以及CUDA实现的细节。通过C++和Python复现实战项目,并探讨了OpenCV viz、CUDA 8.0以上的环境配置。
摘要由CSDN通过智能技术生成

目录

KInectFusion实战笔记 有icp

步骤和条件:

从零开始复现实时三维重建KInectFusion


KInectFusion实战笔记 有icp

KinectFusion实战笔记_kinectfusion python_Stefanie_Song的博客-CSDN博客

GitHub - JingwenWang95/KinectFusion: KinectFusion implemented in Python with PyTorch

步骤和条件:

1.下载数据:freiburg1_desk

2.执行dataset/preprocess.py

然后可以执行kinfu_gui.py

除了重建必要的深度图和彩色图之外,TUM数据集也包含相机轨迹的groundtruth,即在一个固定坐标系下,每一帧图像拍摄时相机的位置和方向坐标。

 

原文链接:https://blog.csdn.net/weixin_43272109/article/details/127099847

需要rgb图,深度图,

depth.txt和groundtruth.txt

 实时三维重建KInectFusion c++

一,从零开始复现实时三维重建KInectFusion
实时三维重建算法
【[本文代码](https://github.com/sky3139/KinectFusion_2022)】
准备环境
准备数据集
检查数据集
计算相机坐标系下的点云
创建一个Patch管理GPU的2D内存
TSDF类
修改后的主函数
最后效果如下
实时三维重建算法
静态:
知乎:三维重建 3D reconstruction 有哪些实用算法?

【本文代码】
准备环境
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

OpenCV: 加上viz编译 ,方便可视化 其他类似的可视化工具 pangolin opengl pcl qglviewer vtk open3d等;
CUDA 8.0 以上 KinectFusion 的复现工作大多基于cuda8.0 在ubuntu20.04 上难以工作,本次复现采用较新的api;
准备数据集
TUM数据集,这里以 f3_long_office为例子
将深度图和RGB图时间同步(后期更新此工具)
检查数据集

#include "read.hpp"
using namespace std;
int main()
{
    DataSet<float> dt("/home/lei/dataset/paper/f3_long_office");
    for (int i = 0; i < dt.pose.frames; i++)
    {
        cv::Mat rgb = cv::imread(dt.color_path[i]);
        cv::Mat depth = cv::imread(dt.depth_path[i]);
        cv::imshow("rgb", rgb);
        cv::imshow("depth", depth);
        cv::waitKey(1);
    }
}



能正确读取rgb图和深度图即可

计算相机坐标系下的点云
定义一个内参结构体

struct Intr
{
    union
    {
        float4 cam;
        struct
        {
            float fx, fy, cx, cy;
        };
    };
    Intr(float4 intr)
    {
        cam = intr;
    }
    __device__ inline float3 cam2world(int u, int v, float z)
    {
        // TODO 这里可预先计算fx,fy倒数,然后计算乘法,应该会快一些
        float x = __fdividef(z * (u - cx), fx);
        float y = __fdividef(z * (v - cy), fy);
        return make_float3(x, y, z);
    }
};


深度图转点云的cuda核函数

__global__ void depth2cam(uint16_t *hd_depth_ptr, float3 *output, Intr intr)
{
    int tx = threadIdx.x; // 640
    int ty = blockIdx.x;  // 480
    int rawidx = tx + ty * 640;
    float pz = hd_depth_ptr[rawidx] * 0.0002f; //深度转换为米
    output[rawidx] = intr.cam2world(tx, ty, pz);
}

main中

int main()
{
    DataSet<float> dt("/home/lei/dataset/paper/f3_long_office");
    ck(cudaGetLastError());
    Intr intr(make_float4(550, 550, 320, 240));
    cv::viz::Viz3d window("map");
    window.showWidget("Coordinate", cv::viz::WCoordinateSystem());

    for (int i = 0; i < dt.pose.frames; i++)
    {
        cv::Mat rgb = cv::imread(dt.color_path[i]);
        cv::Mat depth = cv::imread(dt.depth_path[i], cv::IMREAD_ANYDEPTH);

        uint16_t *hd_depth_ptr;
        cudaMallocManaged((void **)&hd_depth_ptr, depth.rows * depth.cols * sizeof(uint16_t));
        cudaMemcpy(hd_depth_ptr, depth.ptr<uint16_t>(), depth.rows * depth.cols * sizeof(uint16_t), cudaMemcpyHostToDevice);
        float3 *cloud;
        cudaMallocManaged(&cloud, depth.rows * depth.cols * sizeof(float3));
        depth2cam<<<depth.rows, depth.cols>>>(hd_depth_ptr, cloud, intr);
        ck(cudaDeviceSynchronize());
        cv::Mat cpu_cloud(depth.rows * depth.cols, 1, CV_32FC3);
        cudaMemcpy(cpu_cloud.ptr<float *>(), cloud, depth.rows * depth.cols * sizeof(float3), cudaMemcpyDeviceToHost);
        cv::Mat dst2 = rgb.reshape(3,640 * 480);
        window.showWidget("depthmode", cv::viz::WCloud(cpu_cloud, dst2));
        window.spinOnce(true);
        window.spin();
        cv::imshow("rgb", rgb);
        cv::imshow("depth", depth);
        cv::waitKey(1);
        cudaFree(hd_depth_ptr);
        cudaFree(cloud);
    }
}


运行结果如下


创建一个Patch管理GPU的2D内存
template <class T>
struct Patch
{
    T *devPtr;
    size_t pitch = 0;
    size_t rows, cols;
    Patch()
    {
    }
    Patch(int rows, int cols) : rows(rows), cols(cols)
    {
        ck(cudaMallocPitch((void **)&devPtr, &pitch, cols * sizeof(T), rows));
        ck(cudaMemset2D(devPtr, pitch, 0, sizeof(T) * cols, rows));
        // std::cout << pitch << " " << sizeof(T) * cols << std::endl;
    }
    void creat(const int rows, const int cols)
    {
        this->rows = rows;
        this->cols = cols;
        ck(cudaMallocPitch((void **)&devPtr, &pitch, cols * sizeof(T), rows));
        ck(cudaMemset2D(devPtr, pitch, 0, sizeof(T) * cols, rows));
    }
    //拷贝构造函数
    __host__ __device__ Patch(const Patch &lth)
    {
        this->devPtr = lth.devPtr;
        this->rows = lth.rows;
        this->pitch = lth.pitch;
        this->cols = lth.cols;
    }

    ~Patch()
    {
        // cudaFree(devPtr);
    }
    void release()
    {
        cudaFree(devPtr);
    }
    __host__ void upload(const T *host_ptr_arg, size_t host_step_arg)
    {
        ck(cudaMemcpy2D(devPtr, pitch, host_ptr_arg, host_step_arg, cols * sizeof(T), rows, cudaMemcpyHostToDevice));
    }
    __host__ void download(const T *host_ptr_arg, size_t host_step_arg)
    {
        // if (host_step_arg == 0 || devPtr == nullptr || pitch == 0)
        {
            printf("%x,%d %x,%ld\n", host_ptr_arg, host_step_arg, devPtr, pitch);
        }
        ck(cudaMemcpy2D((void *)host_ptr_arg, host_step_arg, devPtr, pitch, sizeof(T) * cols, rows, cudaMemcpyDeviceToHost));
    }
    __device__ inline T &operator()(size_t rows, size_t cols)
    {
        // if (rows < pitch)
        //     return mat[x];
        return *((devPtr + rows * pitch / sizeof(T) + cols));
    }
    __host__ void print()
    {
        printf("%ld %ld %ld\n", pitch, rows, cols);
    }
};

TSDF类
tsdf class

修改后的主函数
int main()
{
    DataSet<float> dt("/home/u20/dataset/paper/f3_long_office");
    ck(cudaGetLastError());

    cv::viz::Viz3d viz1("viz1"), viz2("viz2");
    viz1.showWidget("Coordinate", cv::viz::WCoordinateSystem());

    TSDF tsdf(make_float3(512, 512, 512), make_int2(640, 480));
    tsdf.pintr = new Intr(make_float4(550, 550, 320, 240));
    for (int i = 0; i < dt.pose.frames; i++)
    {
        cv::Mat rgb = cv::imread(dt.color_path[i]);
        cv::Mat depth = cv::imread(dt.depth_path[i], cv::IMREAD_ANYDEPTH);

        tsdf.addScan(depth, rgb);
        std::shared_ptr<Mat> cpu_cloud2;
        Mat cpu_color;
        tsdf.exportCloud(cpu_cloud2, cpu_color);
        viz1.showWidget("depthmode", cv::viz::WCloud(*cpu_cloud2, cpu_color));

        Mat depth_color, cpu_cloud;
        tsdf.depth2cam(depth, rgb, depth_color, cpu_color, cv::Affine3f::Identity());
        cv::Affine3f viewpose = cv::Affine3f::Identity();
        viz1.showWidget("depth", cv::viz::WCloud(depth_color, cpu_color), viewpose.translate(cv::Vec3f(4, 0, 0)));

        // cv::imshow("rgb", rgb);
        // cv::imshow("depth", depth);
        // cv::waitKey(100);
        viz1.spin();
    }
}


最后效果如下

————————————————
版权声明:本文为CSDN博主「SkyTangLei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/LiQuKanNaShiYu/article/details/125016578

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值