点云转深度图:转化,保存,可视化

该博客介绍了如何使用PCL库将点云数据转换为深度图并进行保存及可视化。通过RGBD相机获取的点云数据,可以利用PCL的RangeImage类创建深度图,并通过保存深度图像的RGB PNG文件实现存储。同时,提供了两种方法在PCL可视化器中展示深度图像,一是直接从点云中可视化,二是以图像形式展示深度值。

目录

点云转深度图 测试ok:

越远越黑:

python open3d实现,待测

pcl 三维数据的获取方式

代码展示:在pcl中,把点云转为深度图,并保存和可视化


点云转深度图 测试ok:

远处白色,物体黑色,效果更好:

        lidars=glob.glob(clip_dir+'/lidar/*.pcd')
        lidars=natsorted(lidars)
        
        img_width=3840
        img_height=2160
        for frame_id,lidar_path in enumerate(lidars):
            print('lidar------------',frame_id)
            pts_3d = []
            pts_2d = []
            pcd = o3d.io.read_point_cloud(lidar_path)
            
            # 转换点云为 NumPy 数组
            points = np.asarray(pcd.points)
            pts_3d.append(points[:, :3])
            # pts_3d_to_2d=pts_3d @ lidar2vcs @np.linalg.inv(cam2vcs).T @ K_4x4.T
            
            points_2d= np.hstack((points, np.ones((points.shape[0], 1))))@np.linalg.inv(cam2vcs).T @ K_4x4.T
            
            if 1:
                points_2d[:,[0,1]]/=points_2d[:,[2]]
            
                depth = points_2d[:, 2]  # 深度值

                # 创建深度图,并将所有点初始化为最大深度(如无穷远)
                depth_map = np.full((img_height, img_width), np.inf)

                # 将点云投影到像素坐标
                w = points_2d[:, 0].astype(int)
                h = points_2d[:, 1].astype(int)

                # 过滤点,使得 w 和 h 在图像范围内
                mask = np.logical_and.reduce((w >= 0, w < img_width, h >= 0, h < img_height))
                w, h, depth = w[mask], h[mask], depth[mask]

                # 逐像素赋值深度(最近点优先)
                for i in range(len(w)):
                    if depth_map[h[i], w[i]] > depth[i]:
                        depth_map[h[i], w[i]] = depth[i]

                # 将无穷远的像素设为最大深度值
                max_depth = np.max(depth_map[np.isfinite(depth_map)])
                depth_map[~np.isfinite(depth_map)] = max_depth

                # 归一化到 0-255 并转换为 uint8
                depth_map = (255 * (depth_map / max_depth)).astype(np.uint8)
                
                cv2.imwrite(f'{cur_show_dir}/depth_{frame_id}.png',  depth_map)

越远越黑:

        lidars=glob.glob(clip_dir+'/lidar/*.pcd')
        lidars=natsorted(lidars)
        
        img_width=3840
        img_height=2160
        for frame_id,lidar_path in enumerate(lidars):
            print('lidar------------',frame_id)
            pts_3d = []
            pts_2d = []
            pcd = o3d.io.read_point_cloud(lidar_path)
            
            # 转换点云为 NumPy 数组
            points = np.asarray(pcd.points)
            pts_3d.append(points[:, :3])
            # pts_3d_to_2d=pts_3d @ lidar2vcs @np.linalg.inv(cam2vcs).T @ K_4x4.T
            
            points_2d= np.hstack((points, np.ones((points.shape[0], 1))))@np.linalg.inv(cam2vcs).T @ K_4x4.T
            
            if 1:
                points_2d[:,[0,1]]/=points_2d[:,[2]]
            
                depth = points_2d[:, 2]  # 深度值

                # 创建深度图,并将所有点初始化为最大深度(如无穷远)
                depth_map = np.full((img_height, img_width), np.inf)

                # 将点云投影到像素坐标
                w = points_2d[:, 0].astype(int)
                h = points_2d[:, 1].astype(int)

                # 过滤点,使得 w 和 h 在图像范围内
                mask = np.logical_and.reduce((w >= 0, w < img_width, h >= 0, h < img_height))
                w, h, depth = w[mask], h[mask], depth[mask]

                # 逐像素赋值深度(最近点优先)
                for i in range(len(w)):
                    if depth_map[h[i], w[i]] > depth[i]:
                        depth_map[h[i], w[i]] = depth[i]

                # 将无穷远的像素设为最大深度值
                max_depth = np.max(depth_map[np.isfinite(depth_map)])
                depth_map[~np.isfinite(depth_map)] = 0
                # 归一化到 0-255 并转换为 uint8
                depth_map = (255 * (depth_map / max_depth)).astype(np.uint8)
                
                cv2.imwrite(f'{cur_show_dir}/depth_{frame_id}.png',  depth_map)

python open3d实现,待测

import open3d as o3d
import numpy as np
import cv2

# 加载点云数据
pcd = o3d.io.read_point_cloud("your_point_cloud_file.ply")  # 替换为你的点云文件路径

# 设置相机内参
camera_intrinsics = o3d.camera.PinholeCameraIntrinsic(width=640, height=480, fx=525, fy=525, cx=320, cy=240)

# 设置相机外参(这里假设无旋转和平移)
R = np.eye(3)  # 3x3 旋转矩阵(单位矩阵)
t = np.array([0, 0, 0])  # 3x1 平移向量(零向量)

# 创建变换矩阵
extrinsics = np.eye(4)
extrinsics[:3, :3] = R
extrinsics[:3, 3] = t

# 使用外参将点云转换到相机坐标系
pcd.transform(extrinsics)

# 将点云转换为深度图
depth_map = o3d.geometry.PointCloud.create_depth_image_from_point_cloud_with_intrinsics(
    pcd, camera_intrinsics, depth_scale=1000.0, depth_trunc=3.0, stride=1
)

# 将深度图转换为NumPy数组
depth_image = np.asarray(depth_map)

# 将深度图归一化到0-255并转换为8位图像
depth_image = cv2.normalize(depth_image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)

# 使用 OpenCV 显示深度图
cv2.imshow("Depth Image", depth_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 保存深度图
cv2.imwrite("depth_image.png", depth_image)

pcl 三维数据的获取方式


RGBD相机和深度图
代码展示:在pcl中,把点云转为深度图,并保存和可视化
三维数据的获取方式
在计算机视觉和遥感领域,点云可以通过四种主要的技术获得,
(1)根据图像衍生而得,比如通过双目相机,
(2)基于RGBD相机获取点云
(3)基于光探测距离和测距系统比如lidar,
(4)Synthetic Aperture Radar (SAR)系统获取,基于这些不同的原理系统获取的点云数据,其数据的特征和应用的范围也是多种多样

RGBD相机和深度图
(1)深度图的原理:用深度值z值 当作像素值
(2)深度图获取原理:

代码展示:在pcl中,把点云转为深度图,并保存和可视化

#include <iostream>
#include <pcl/io/pcd_io.h> 
#include <pcl/common/common_headers.h>
#include <pcl/range_image/range_image.h> //点云转深度头文件
#include <pcl/visualization/range_image_visualizer.h> //深度图像可视化
#include <pcl/visualization/pcl_visualizer.h>//点云可视化
#include <boost/thread/thread.hpp>//多线程
#include <pcl/io/png_io.h>//保存深度图像
#include <pcl/visualization/common/float_image_utils.h>//保存深度图像
int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr pointCloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("D:/zmy_719/vs_pcl/bun0.pcd", *pointCloud);

    //以1度为角分辨率,从上面创建的点云创建深度图像。
    //深度图像中的一个像素对应的角度大小1°,角度转弧度
    float angularResolution = (float)(1.0f * (M_PI / 180.0f));
    
    // 360.0度转弧度,扫描的水平宽度是360°
    float maxAngleWidth = (float)(360.0f * (M_PI / 180.0f));

    // 180.0度转弧度,扫描的垂直高度是180°
    float maxAngleHeight = (float)(180.0f * (M_PI / 180.0f));

    //采集位置,传感器的初始位姿
    Eigen::Affine3f sensorPose = (Eigen::Affine3f)Eigen::Translation3f(0.0f, 0.0f, 0.0f);
    
    //选择的系统 X轴是向右,Y轴向下,Z轴向前
    //如果选择是LASER_FRAME,则X轴向前,Y轴向左,Z轴向上
    pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;
    
    //noiseLevel如果设置为0.05就是5cm为半径的圆内的所有点的平均值,得到的深度值为准
    float noiseLevel = 0.00;

    //minRange大于0,假设为r,那么r内的所有点被忽略,为盲区
    float minRange = 0.0f;
    int borderSize = 1;

    //-------------------生成深度图像------------------------
    pcl::RangeImage::Ptr rangeImage_ptr(new pcl::RangeImage);
    pcl::RangeImage& rangeImage = *rangeImage_ptr;
    rangeImage.createFromPointCloud(*pointCloud, angularResolution, maxAngleWidth, maxAngleHeight, sensorPose, coordinate_frame, noiseLevel, minRange, borderSize);
    //-------------------读取深度图像信息------------------------
    std::cout << rangeImage << "\n";

    //-------------------深度图的保存------------------------
    float* ranges = rangeImage.getRangesArray();
    unsigned char* rgb_image = pcl::visualization::FloatImageUtils::getVisualImage(ranges, rangeImage.width, rangeImage.height);
    pcl::io::saveRgbPNGFile("RangeImage.png", rgb_image, rangeImage.width, rangeImage.height);

    //------------------可视化点云----------------------
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer1(new pcl::visualization::PCLVisualizer("PointCloud Viewer"));
    //设置背景颜色
    viewer1->setBackgroundColor(0, 0, 0);
    //添加点云
    viewer1->addPointCloud(pointCloud, "point cloud");
    viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 0, 1, "point cloud");
    viewer1->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "point cloud");
        
    //------------------可视化深度图像----------------------
    //方法一:从点云中可视化深度图像
    boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer(new pcl::visualization::PCLVisualizer("RangeImage Viewer"));
    viewer->setBackgroundColor(0, 0, 0);  //设置背景颜色为黑色
    pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointWithRange> range_image_color_handler(rangeImage_ptr, "z");
    viewer->addPointCloud(rangeImage_ptr, range_image_color_handler, "range image");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "range image");
    viewer->initCameraParameters();

    //方法二:以图像的形式显示深度图像,深度值作为颜色显示
    pcl::visualization::RangeImageVisualizer range_image_widget("Range image");
    range_image_widget.setWindowTitle("RangeImage");
    range_image_widget.showRangeImage(rangeImage);
    range_image_widget.setSize(1000, 1000);

        while (!viewer->wasStopped())
        {
            viewer->spinOnce(100);
            boost::this_thread::sleep(boost::posix_time::microseconds(100000));
        }

    system("pause");
    return 0;
}



结果展示:

代码参考:PCL官网

原文链接:https://blog.csdn.net/adfjadsklf/article/details/119082844

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值