You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python实现无舍入的3D numpy数组旋转?

解决3D离散体素数组的无近似旋转问题

我完全懂你的需求——你的3D数组是离散的体素集合,每个体素对应明确的材料类型,旋转时绝对不能通过插值生成近似的材料值,必须保留原始的离散材料类别,哪怕最终结果有“块状”模糊也没关系。

下面是一套完全基于精确坐标变换、无插值无近似舍入的实现方案:

1. 核心思路

我们不依赖现成的插值旋转函数,而是手动完成坐标变换+体素映射:

  • 先计算原始体素中心的坐标(相对于数组中心,避免旋转后偏移)
  • 应用精确的旋转矩阵到每个体素的中心坐标
  • 将旋转后的坐标映射到新数组的整数索引(直接取整,不做任何插值混合)
  • 构建新数组,把原始体素的材料值精准放到旋转后的对应位置

2. 具体实现步骤

步骤1:定义精确3D旋转矩阵

根据你需要的旋转角度,生成无近似的旋转矩阵(以绕X/Y/Z轴为例):

import numpy as np

def get_rotation_matrix(angle_x=0, angle_y=0, angle_z=0):
    # 角度转弧度(精确计算)
    rx = np.radians(angle_x)
    ry = np.radians(angle_y)
    rz = np.radians(angle_z)
    
    # 绕X轴旋转矩阵
    Rx = np.array([
        [1, 0, 0],
        [0, np.cos(rx), -np.sin(rx)],
        [0, np.sin(rx), np.cos(rx)]
    ])
    
    # 绕Y轴旋转矩阵
    Ry = np.array([
        [np.cos(ry), 0, np.sin(ry)],
        [0, 1, 0],
        [-np.sin(ry), 0, np.cos(ry)]
    ])
    
    # 绕Z轴旋转矩阵
    Rz = np.array([
        [np.cos(rz), -np.sin(rz), 0],
        [np.sin(rz), np.cos(rz), 0],
        [0, 0, 1]
    ])
    
    # 组合旋转矩阵(顺序:Z→Y→X,可根据需求调整)
    R = Rz @ Ry @ Rx
    return R

步骤2:体素坐标映射与旋转实现

def rotate_voxel_array(arr, angle_x=0, angle_y=0, angle_z=0):
    # 获取原始数组尺寸
    x_dim, y_dim, z_dim = arr.shape
    
    # 生成原始体素的中心坐标(原点设为数组中心,避免旋转后偏移)
    x_coords = np.arange(x_dim) - x_dim/2 + 0.5
    y_coords = np.arange(y_dim) - y_dim/2 + 0.5
    z_coords = np.arange(z_dim) - z_dim/2 + 0.5
    xx, yy, zz = np.meshgrid(x_coords, y_coords, z_coords, indexing='ij')
    
    # 整理为N×3的坐标矩阵
    coords = np.stack([xx.flatten(), yy.flatten(), zz.flatten()], axis=1)
    
    # 应用旋转矩阵
    R = get_rotation_matrix(angle_x, angle_y, angle_z)
    rotated_coords = coords @ R.T
    
    # 计算新数组的尺寸(确保能容纳所有旋转后的体素)
    min_x, max_x = rotated_coords[:,0].min(), rotated_coords[:,0].max()
    min_y, max_y = rotated_coords[:,1].min(), rotated_coords[:,1].max()
    min_z, max_z = rotated_coords[:,2].min(), rotated_coords[:,2].max()
    
    new_x_dim = int(np.ceil(max_x - min_x))
    new_y_dim = int(np.ceil(max_y - min_y))
    new_z_dim = int(np.ceil(max_z - min_z))
    
    # 将旋转后的坐标偏移到新数组的索引范围(左上角为原点)
    rotated_coords[:,0] -= min_x - 0.5
    rotated_coords[:,1] -= min_y - 0.5
    rotated_coords[:,2] -= min_z - 0.5
    
    # 转换为整数索引(直接取整,无任何近似插值)
    rotated_indices = np.round(rotated_coords).astype(int)
    
    # 过滤越界索引
    valid_mask = (
        (rotated_indices[:,0] >= 0) & (rotated_indices[:,0] < new_x_dim) &
        (rotated_indices[:,1] >= 0) & (rotated_indices[:,1] < new_y_dim) &
        (rotated_indices[:,2] >= 0) & (rotated_indices[:,2] < new_z_dim)
    )
    
    # 初始化新数组(用原始数组的默认填充值,比如0表示空)
    rotated_arr = np.zeros((new_x_dim, new_y_dim, new_z_dim), dtype=arr.dtype)
    
    # 映射原始体素值到新数组
    original_vals = arr.flatten()[valid_mask]
    valid_indices = rotated_indices[valid_mask]
    rotated_arr[valid_indices[:,0], valid_indices[:,1], valid_indices[:,2]] = original_vals
    
    return rotated_arr

步骤3:关键说明

  • 无近似保证:整个过程仅做精确的矩阵乘法坐标变换和整数取整映射,没有任何插值操作,所有材料值都是原始数组中的离散值,完全没有舍入生成的近似值。
  • 关于模糊:因为是直接映射体素,旋转后的结果会有“块状锯齿”效果,但这正是你需要的——材料属性完全准确,模糊不影响。
  • 自定义旋转轴:如果需要绕任意轴旋转,可修改get_rotation_matrix函数,用Rodrigues旋转公式生成任意轴的精确旋转矩阵即可。

3. 使用示例

假设你有一个3D立方体体素数组,要绕Y轴旋转45度:

# 创建示例3D立方体(1表示材料A,0表示空)
voxel_obj = np.zeros((10,10,10), dtype=int)
voxel_obj[2:8, 2:8, 2:8] = 1

# 绕Y轴旋转45度
rotated_obj = rotate_voxel_array(voxel_obj, angle_y=45)

这样得到的rotated_obj中所有非零值都是原始的1,没有任何近似值,完全符合你的需求。

内容的提问来源于stack exchange,提问作者Toykan Ozdeger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:28:13