关于把图像中pixel投影到3d点云,附着在dsm模型上的任务

目标是将图像的像素信息映射到三维点云上,然后将这些信息附着到数字表面模型(DSM)上。下面是一个粗略的解决方案:

1. 加载DSM和光学图像

使用rasterio来读取提供的DSM和图像(.tif格式),以及相机的RPC参数。

import rasterio
import numpy as np
import json

# 读取DSM
with rasterio.open('dsm_model.tif') as dsm:
    dsm_data = dsm.read(1)  # 获取DSM数据,通常是地面高程数据

# 读取光学图像
with rasterio.open('optical_image.tif') as img:
    img_data = img.read(1)  # 获取光学图像数据

2. 加载相机参数(RPC)

读取存储在JSON文件中的相机参数,包括行列偏移、比例因子以及地理坐标的转换矩阵等。

# 读取相机参数JSON文件
with open('camera_params.json', 'r') as f:
    camera_params = json.load(f)

rpc = camera_params['rpc']  # 获取RPC相关参数

3. 计算像素到地理坐标的投影

使用RPC模型将图像中的每个像素坐标(行列坐标)映射到地理坐标系统中。RPC是通过行列和地理坐标(经纬度、高程)之间的多项式关系进行转换的。

RPC的模型参数包括row_numcol_numrow_dencol_den等,它们可以计算出每个像素在地理坐标系中的位置。可以根据这些参数实现反向投影:

def rpc_projection(row, col, rpc):
    """
    使用RPC参数将图像中的(row, col)像素投影到地理坐标系中。
    """
    row_offset, col_offset, lat_offset, lon_offset, alt_offset = (
        rpc['row_offset'], rpc['col_offset'], rpc['lat_offset'], 
        rpc['lon_offset'], rpc['alt_offset']
    )
    
    row_scale, col_scale, lat_scale, lon_scale, alt_scale = (
        rpc['row_scale'], rpc['col_scale'], rpc['lat_scale'],
        rpc['lon_scale'], rpc['alt_scale']
    )

    # 通过RPC公式计算地理坐标
    lat = lat_offset + row_scale * (row - row_offset)
    lon = lon_offset + col_scale * (col - col_offset)
    alt = alt_offset + alt_scale * (row - row_offset)  # 假设altitude以行变化

    return lat, lon, alt

# 计算像素对应的地理坐标
lat, lon, alt = rpc_projection(row=100, col=150, rpc=rpc)  # 假设我们计算(100,150)像素

4. 从DSM模型获取高度信息

DSM已经包含了每个位置的高程信息,可以从DSM中获取每个像素位置的高度数据。在得到像素对应的地理坐标后,获取DSM上该点的高度并将其作为Z值。

# 使用地理坐标查找DSM上的高程
def get_dsm_height(lat, lon, dsm, img):
    """根据经纬度从DSM获取高程"""
    # 假设你有一个函数将经纬度转换为图像的行列坐标
    row, col = latlon_to_pixel(lat, lon, img)  # 需要实现此函数
    return dsm[int(row), int(col)]  # 返回DSM对应位置的高度值

# 获取DSM高度
height = get_dsm_height(lat, lon, dsm_data, img)

5. 映射像素到3D点云

使用从RPC和DSM得到的地理坐标和高度信息,构建出三维点云。每个像素点在三维空间中都有一个位置 (lon, lat, height)。

def map_pixel_to_3d(row, col, rpc, dsm, img):
    # 获取像素对应的地理坐标
    lat, lon, _ = rpc_projection(row, col, rpc)
    # 获取DSM中的高度
    height = get_dsm_height(lat, lon, dsm, img)
    return lat, lon, height

# 假设我们遍历图像中的所有像素,并将其映射到3D
points = []
for row in range(img_data.shape[0]):
    for col in range(img_data.shape[1]):
        lat, lon, height = map_pixel_to_3d(row, col, rpc, dsm_data, img)
        points.append((lat, lon, height))

6. 将光学图像附着到3D点云

最后,将光学图像的像素附着到这些三维点云上。可以使用像素的灰度值或颜色值作为纹理映射到对应的三维点上。

def attach_texture_to_point_cloud(points, img_data):
    # 将光学图像的颜色值附加到3D点云
    textured_points = []
    for i, (lat, lon, height) in enumerate(points):
        color = img_data[int(lat), int(lon)]  # 假设color是图像的颜色值
        textured_points.append((lat, lon, height, color))
    return textured_points

# 附加纹理到点云
textured_points = attach_texture_to_point_cloud(points, img_data)

7. 可视化点云

使用点云库(如Open3D)进行可视化,显示附着纹理的三维点云。

import open3d as o3d

# 创建Open3D点云对象
pcd = o3d.geometry.PointCloud()

# 将点云数据添加到点云对象
points = np.array([point[:3] for point in textured_points])
colors = np.array([point[3] for point in textured_points])  # 获取纹理颜色信息
pcd.points = o3d.utility.Vector3dVector(points)
pcd.colors = o3d.utility.Vector3dVector(colors)

# 可视化点云
o3d.visualization.draw_geometries([pcd])

总结

  1. 读取DSM和光学图像。
  2. 使用RPC参数将图像像素映射到地理坐标系统。
  3. 从DSM中获取对应位置的高度信息。
  4. 将这些信息作为三维坐标生成点云。
  5. 使用光学图像的像素颜色值作为纹理附加到点云上。
  6. 使用Open3D进行可视化。
在2D与3D融合的点云标注项目中,**将2D图像坐标映射到3D点云**是一个典型的跨模态数据对齐问题。其核心在于利用相机的内外参矩阵,将2D图像上的像素坐标(u, v)通过投影变换转换为3D空间中的点。 --- ## ✅ 实现思路: ### 1. 前提条件: - 已知相机的 **内参矩阵**(Intrinsic Matrix):`K` - 已知相机的 **外参矩阵**(Extrinsic Matrix),即相机相对于LiDAR坐标系的旋转和平移矩阵:`[R|t]` - 获取了对应的 **深度图**(Depth Map)或 **点云数据** --- ## 🧠 步骤详解: ### 步骤一:获取2D图像中的像素坐标 (u, v) 例如用户在图像中标记了一个矩形框,我们从中提取出一个像素点 `(u, v)`,比如目标物体中心点。 ```python u = 320 # 图像x坐标 v = 240 # 图像y坐标 ``` --- ### 步骤二:从深度图中获取该点的深度值 `d` 假设你有一张与图像同步的深度图 `depth_map`,你可以直接获取该点的深度值: ```python d = depth_map[v, u] # 注意是 [行, 列] ``` > 如果没有深度图,则需要通过 LiDAR 点云反向投影找到最近的3D点,详见“相关问题”。 --- ### 步骤三:使用相机内参矩阵将像素坐标转为相机坐标系下的3D点 相机内参矩阵通常如下: $$ K = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} $$ 我们可以将其表示为 NumPy 数组: ```python import numpy as np K = np.array([ [fx, 0, cx], [0, fy, cy], [0, 0, 1] ]) ``` 然后计算归一化相机坐标系下的方向向量: ```python uv1 = np.array([u, v, 1]) # 齐次坐标 xyz_camera = np.linalg.inv(K) @ uv1 * d # 投影回相机坐标系 ``` 得到的是以相机为中心的3D坐标 `(x, y, z)`。 --- ### 步骤四:将相机坐标系下的点转换为LiDAR坐标系(或其他统一坐标系) 我们需要相机相对于LiDAR的外参矩阵 `[R|t]`: ```python R = ... # 3x3 旋转矩阵 t = ... # 3x1 平移向量 point_camera = np.array([x, y, z]) # 转换到LiDAR坐标系 point_lidar = R.T @ (point_camera - t) ``` 或者如果外参是 LiDAR 到相机的变换矩阵 `T_cam_from_lidar`,则使用: ```python T_cam_from_lidar = ... # 4x4 变换矩阵 point_lidar_homogeneous = np.append(point_lidar, 1) point_camera_homogeneous = T_cam_from_lidar @ point_lidar_homogeneous ``` --- ## 📦 示例代码整合版: ```python def pixel_to_point(u, v, depth_map, K, R, t): # 获取深度值 d = depth_map[v, u] # 构造齐次坐标 uv1 = np.array([u, v, 1]) # 计算相机坐标系下的3D点 xyz_camera = np.linalg.inv(K) @ uv1 * d # 转换到LiDAR坐标系 xyz_lidar = R.T @ (xyz_camera - t) return xyz_lidar ``` --- ## 🔁 相关问题:
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ajaxm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值