Apply multi-view transform to normals (rotation only). Consistent with test_ovoxel_pbr_transform.py implementation. Args: normals: torch.Tensor or np.ndarray, shape [N, 3] or [N, 3, 3] frame: dict containing transform_matrix Returns: transformed_normals: np
(normals, frame)
| 76 | |
| 77 | |
| 78 | def transform_normals(normals, frame): |
| 79 | """ |
| 80 | Apply multi-view transform to normals (rotation only). |
| 81 | Consistent with test_ovoxel_pbr_transform.py implementation. |
| 82 | |
| 83 | Args: |
| 84 | normals: torch.Tensor or np.ndarray, shape [N, 3] or [N, 3, 3] |
| 85 | frame: dict containing transform_matrix |
| 86 | |
| 87 | Returns: |
| 88 | transformed_normals: np.ndarray (always returns numpy for dump compatibility) |
| 89 | """ |
| 90 | is_numpy = isinstance(normals, np.ndarray) |
| 91 | if is_numpy: |
| 92 | normals = torch.from_numpy(normals).float() |
| 93 | |
| 94 | device = normals.device |
| 95 | original_shape = normals.shape |
| 96 | |
| 97 | # Flatten to [N, 3] for processing |
| 98 | if len(original_shape) == 3: |
| 99 | normals_flat = normals.reshape(-1, 3) |
| 100 | else: |
| 101 | normals_flat = normals |
| 102 | |
| 103 | c2w_orig = torch.tensor(frame['transform_matrix'], dtype=torch.float32, device=device) |
| 104 | |
| 105 | # Old and new camera matrices |
| 106 | radius = c2w_orig[:3, 3].norm().item() |
| 107 | c2w_new = get_new_camera_matrix(radius=radius, yaw=-90/180.0*math.pi, pitch=0.0, |
| 108 | dtype=torch.float32, device=device) |
| 109 | w2c_orig = torch.inverse(c2w_orig) |
| 110 | |
| 111 | # Axis alignment matrices (rotation part only, 3x3) |
| 112 | R_init = torch.tensor([ |
| 113 | [1.0, 0.0, 0.0], |
| 114 | [0.0, 0.0, -1.0], |
| 115 | [0.0, 1.0, 0.0] |
| 116 | ], dtype=torch.float32, device=device) |
| 117 | |
| 118 | R_back = torch.tensor([ |
| 119 | [1.0, 0.0, 0.0], |
| 120 | [0.0, 0.0, 1.0], |
| 121 | [0.0, -1.0, 0.0] |
| 122 | ], dtype=torch.float32, device=device) |
| 123 | |
| 124 | R_ply = torch.tensor([ |
| 125 | [1.0, 0.0, 0.0], |
| 126 | [0.0, 0.0, 1.0], |
| 127 | [0.0, -1.0, 0.0] |
| 128 | ], dtype=torch.float32, device=device) |
| 129 | |
| 130 | # Use rotation part only |
| 131 | T_cam_rot = c2w_new[:3, :3] @ w2c_orig[:3, :3] @ R_ply |
| 132 | T_final_rot = R_back @ T_cam_rot @ R_init |
| 133 | |
| 134 | # Apply rotation transform |
| 135 | normals_trans = torch.matmul(normals_flat, T_final_rot.T) |
no test coverage detected