3d点云数据转2d平面图像

3d点云映射到2d方法

方法

基于法向量与三个坐标系平面夹角的余弦值得到三张点云数据的映射

  1. 输入数据: 输入三维点云数据,每个点的坐标和法向量。
  2. 计算法向量余弦值: 对于每个点,计算其法向量与三个坐标系平面的夹角余弦值。
    假设法向量为 N → = ( N x , N y , N z ) \overrightarrow{N}=(N_x,N_y,N_z) N =(Nx,Ny,Nz) ,对于三个坐标系平面,其余弦值计算如下:
  • 以 X 轴为法向量:
    c o s ( θ x ) = N x ∥ N ∥ cos(\theta_x)=\frac{N_x}{\|N\|} cos(θx)=NNx
  • 以 Y 轴为法向量:
    c o s ( θ y ) = N y ∥ N ∥ cos(\theta_y)=\frac{N_y}{\|N\|} cos(θy)=NNy
  • 以 Z 轴为法向量:
    c o s ( θ z ) = N z ∥ N ∥ cos(\theta_z)=\frac{N_z}{\|N\|} cos(θz)=NNz
    其中, ∥ N ∥ \|N\| N表示法向量的模。
  1. 选择映射平面: 对于每个点,选择余弦值最大的坐标系平面作为映射平面。即,对于每个点,比较 c o s ( θ x ) cos(\theta_x) cos(θx) c o s ( θ y ) cos(\theta_y) cos(θy),和 c o s ( θ z ) cos(\theta_z) cos(θz),选择最大的那个对应的坐标系平面。
  2. 映射到平面: 将每个点投影到选择的映射平面上。这可以通过将点的坐标投影到相应的坐标系平面上来实现。如果选择了 X 轴为映射平面,那么投影后的坐标为 ( 0 , Y , Z ) (0,Y,Z) (0,Y,Z);选择 Y 轴为映射平面,则投影后的坐标为 ( X , 0 , Z ) (X,0,Z) (X,0,Z);选择 Z 轴为映射平面,则投影后的坐标为 ( X , Y , 0 ) (X,Y,0) (X,Y,0)
  3. 生成映射平面图: 将所有点映射到平面上后,生成映射平面图,可以通过在二维空间上绘制点的坐标来实现
import open3d as o3d
import numpy as np
import cv2

def img_norm(img):
    img_max = (img[img != 0]).max()
    img_min = (img[img != 0]).min()
    img_new = (img-img_min)*255.0/(img_max-img_min)
    th = (0-img_min)*255.0/(img_max - img_min)
    img_new[img_new==th] = 0
    img_new = cv2.medianBlur(img_new.astype(np.float32), 3)
    return img_new

def point_cloud_to_image(point_cloud_path, image_path):
    # 读取点云数据
    pcd = o3d.io.read_point_cloud(point_cloud_path)
    points = np.asarray(pcd.points)
    

    # 检查点云是否为空
    if len(points) == 0:
        print("错误:点云为空。")
        return None
    
    # y轴则为垂直深度方向,使用z轴作为y, 
    # 剔除 points[:, 1] 大于深度中值的点
    # depth_threshold = np.median(points[:, 1])
    # 找到x轴上最大值的点的索引
    max_x_index = np.argmax(points[:, 0])
    # 得到对应的y轴的值
    corresponding_y_value = points[max_x_index, 1]
    filtered_points = points[points[:, 1] <= corresponding_y_value]
    
    print(filtered_points)
    # 生成一个 Open3D 点云对象
    filtered_point_cloud = o3d.geometry.PointCloud()

    # 将 NumPy 数组转换为 Open3D 点云
    filtered_point_cloud.points = o3d.utility.Vector3dVector(filtered_points)
    # 估算法线
    filtered_point_cloud.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=2, max_nn=50))
    
    # 获取法线和点坐标
    normals = np.asarray(filtered_point_cloud.normals)
    print(normals)
    # 计算每个点法向量与三维空间三个平面的夹角余弦值
    cosines_x = normals[:, 0]
    cosines_y = normals[:, 1]
    cosines_z = normals[:, 2]
    
    
    
    # 计算点云的深度信息
    depth = filtered_points[:, 1]  
#     normalized_depth = (depth - np.min(depth)) / (np.max(depth) - np.min(depth))

#     # 将深度信息映射到[0, 255]
#     depth_channel = (normalized_depth * 255).astype(np.uint8)

    # 获取点云的范围
    min_x, max_x = np.min(filtered_points[:, 0]), np.max(filtered_points[:, 0])
    min_z, max_z = np.min(filtered_points[:, 2]), np.max(filtered_points[:, 2])  
    print(min_x, max_x)
    print(min_z, max_z)
    print(np.min(filtered_points[:, 1]), np.max(filtered_points[:, 1]))
    # 计算图像尺寸
    image_width = int(max_x - min_x) + 1
    image_height = int(max_z - min_z) + 1
    print(image_width)
    print(image_height)
    
    # 创建图像
    depth_image = np.zeros((image_height, image_width))
    x_cosin_img = np.zeros((image_height, image_width))
    y_cosin_img = np.zeros((image_height, image_width))
    z_cosin_img = np.zeros((image_height, image_width))
    rst_img = np.zeros((image_height, image_width, 3))
    print(depth_image.shape)
    
    # 将深度信息填充到深度图像中
    for x, y, z, x_ar, y_ar, z_ar in zip(filtered_points[:, 0], filtered_points[:, 1], filtered_points[:, 2], cosines_x, cosines_y, cosines_z):

        depth_image[int(z-min_z), int(x-min_x)] = y
        x_cosin_img[int(z-min_z), int(x-min_x)] = x_ar
        y_cosin_img[int(z-min_z), int(x-min_x)] = y_ar
        z_cosin_img[int(z-min_z), int(x-min_x)] = z_ar
    
#     print("x_cosin_img:",x_cosin_img)
#     print("x_cosin_img:",x_cosin_img.max())
    depth_image = img_norm(depth_image)
    x_cosin_img = img_norm(x_cosin_img)
    y_cosin_img = img_norm(y_cosin_img)
    z_cosin_img = img_norm(z_cosin_img)
    # 保存深度图像
    cv2.imwrite('depth_image.jpg', depth_image)
    cv2.imwrite('x_cosin_img.jpg', x_cosin_img)
    cv2.imwrite('y_cosin_img.jpg', y_cosin_img)
    cv2.imwrite('z_cosin_img.jpg', z_cosin_img)
    rst_img[:,:,0] = depth_image
    rst_img[:,:,1] = x_cosin_img
    rst_img[:,:,2] = z_cosin_img
    cv2.imwrite("rst.jpg", rst_img)
#     return depth_image

# 示例用法
point_cloud_to_image(skin_path, 'depth_image.jpg')

  • 25
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2D激光点云数据与RGB图像信息的融合是一种将激光点云数据与图像信息结合起来的技术,旨在获得3D环境的更全面和精确的信息。 首先,激光点云数据是通过激光雷达扫描周围环境而获取的大量点云数据。这些数据包含了每个点的位置信息和反射强度等属性。然而,仅仅依靠点云数据无法完全描述场景细节,因为它无法提供对象的纹理、颜色、光照等信息。 而RGB图像则能够提供物体的视觉外观信息,包括纹理、颜色、光照等。通过图像传感器获取的RGB图像可以提供丰富的视觉细节,但它无法提供物体的准确的空间位置信息。 因此,2D激光点云数据与RGB图像信息的融合就是将这两种数据进行融合,以获得更丰富、准确和完整的3D环境信息。 融合的方式包括两个步骤:首先,将RGB图像与激光点云进行对齐。这可以通过激光雷达和相机之间的外部或内部参数进行校准来实现。对齐后,可以将每个点的颜色信息与其对应的点云数据进行匹配。 其次,通过融合算法将点云数据和RGB图像进行融合。常用的方法包括投影法、插值法和特征提取等。投影法将点云数据映射到图像平面上,然后将图像上的颜色信息赋给相应的点云数据。插值法利用点云和图像之间的一致性来填充点云数据中的颜色信息。特征提取法则通过提取图像和点云中的共同特征来进行融合。 最终,通过2D激光点云数据与RGB图像信息的融合,可以得到更加真实和细致的3D环境信息。这种技术在机器人导航、虚拟现实和增强现实等领域具有广泛的应用前景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值