|
4 | 4 | # This source code is licensed under the BSD-style license found in the
|
5 | 5 | # LICENSE file in the root directory of this source tree.
|
6 | 6 |
|
7 |
| -import logging |
8 | 7 | from typing import Tuple
|
9 | 8 |
|
10 | 9 | import torch
|
11 | 10 |
|
12 | 11 | from ..renderer import PerspectiveCameras
|
13 |
| -from ..transforms import matrix_to_rotation_6d |
14 |
| - |
15 |
| - |
16 |
| -LOGGER = logging.getLogger(__name__) |
| 12 | +from ..renderer.camera_conversions import ( |
| 13 | + _cameras_from_opencv_projection, |
| 14 | + _opencv_from_cameras_projection, |
| 15 | + _pulsar_from_cameras_projection, |
| 16 | + _pulsar_from_opencv_projection, |
| 17 | +) |
17 | 18 |
|
18 | 19 |
|
19 | 20 | def cameras_from_opencv_projection(
|
@@ -58,30 +59,7 @@ def cameras_from_opencv_projection(
|
58 | 59 | Returns:
|
59 | 60 | cameras_pytorch3d: A batch of `N` cameras in the PyTorch3D convention.
|
60 | 61 | """
|
61 |
| - focal_length = torch.stack([camera_matrix[:, 0, 0], camera_matrix[:, 1, 1]], dim=-1) |
62 |
| - principal_point = camera_matrix[:, :2, 2] |
63 |
| - |
64 |
| - # Retype the image_size correctly and flip to width, height. |
65 |
| - image_size_wh = image_size.to(R).flip(dims=(1,)) |
66 |
| - |
67 |
| - # Get the PyTorch3D focal length and principal point. |
68 |
| - focal_pytorch3d = focal_length / (0.5 * image_size_wh) |
69 |
| - p0_pytorch3d = -(principal_point / (0.5 * image_size_wh) - 1) |
70 |
| - |
71 |
| - # For R, T we flip x, y axes (opencv screen space has an opposite |
72 |
| - # orientation of screen axes). |
73 |
| - # We also transpose R (opencv multiplies points from the opposite=left side). |
74 |
| - R_pytorch3d = R.clone().permute(0, 2, 1) |
75 |
| - T_pytorch3d = tvec.clone() |
76 |
| - R_pytorch3d[:, :, :2] *= -1 |
77 |
| - T_pytorch3d[:, :2] *= -1 |
78 |
| - |
79 |
| - return PerspectiveCameras( |
80 |
| - R=R_pytorch3d, |
81 |
| - T=T_pytorch3d, |
82 |
| - focal_length=focal_pytorch3d, |
83 |
| - principal_point=p0_pytorch3d, |
84 |
| - ) |
| 62 | + return _cameras_from_opencv_projection(R, tvec, camera_matrix, image_size) |
85 | 63 |
|
86 | 64 |
|
87 | 65 | def opencv_from_cameras_projection(
|
@@ -114,27 +92,7 @@ def opencv_from_cameras_projection(
|
114 | 92 | tvec: A batch of translation vectors of shape `(N, 3)`.
|
115 | 93 | camera_matrix: A batch of camera calibration matrices of shape `(N, 3, 3)`.
|
116 | 94 | """
|
117 |
| - R_pytorch3d = cameras.R.clone() # pyre-ignore |
118 |
| - T_pytorch3d = cameras.T.clone() # pyre-ignore |
119 |
| - focal_pytorch3d = cameras.focal_length |
120 |
| - p0_pytorch3d = cameras.principal_point |
121 |
| - T_pytorch3d[:, :2] *= -1 |
122 |
| - R_pytorch3d[:, :, :2] *= -1 |
123 |
| - tvec = T_pytorch3d |
124 |
| - R = R_pytorch3d.permute(0, 2, 1) |
125 |
| - |
126 |
| - # Retype the image_size correctly and flip to width, height. |
127 |
| - image_size_wh = image_size.to(R).flip(dims=(1,)) |
128 |
| - |
129 |
| - principal_point = (-p0_pytorch3d + 1.0) * (0.5 * image_size_wh) # pyre-ignore |
130 |
| - focal_length = focal_pytorch3d * (0.5 * image_size_wh) |
131 |
| - |
132 |
| - camera_matrix = torch.zeros_like(R) |
133 |
| - camera_matrix[:, :2, 2] = principal_point |
134 |
| - camera_matrix[:, 2, 2] = 1.0 |
135 |
| - camera_matrix[:, 0, 0] = focal_length[:, 0] |
136 |
| - camera_matrix[:, 1, 1] = focal_length[:, 1] |
137 |
| - return R, tvec, camera_matrix |
| 95 | + return _opencv_from_cameras_projection(cameras, image_size) |
138 | 96 |
|
139 | 97 |
|
140 | 98 | def pulsar_from_opencv_projection(
|
@@ -170,90 +128,7 @@ def pulsar_from_opencv_projection(
|
170 | 128 | convention `(N, 13)` (3 translation, 6 rotation, focal_length, sensor_width,
|
171 | 129 | c_x, c_y).
|
172 | 130 | """
|
173 |
| - assert len(camera_matrix.size()) == 3, "This function requires batched inputs!" |
174 |
| - assert len(R.size()) == 3, "This function requires batched inputs!" |
175 |
| - assert len(tvec.size()) in (2, 3), "This function reuqires batched inputs!" |
176 |
| - |
177 |
| - # Validate parameters. |
178 |
| - image_size_wh = image_size.to(R).flip(dims=(1,)) |
179 |
| - assert torch.all( |
180 |
| - image_size_wh > 0 |
181 |
| - ), "height and width must be positive but min is: %s" % ( |
182 |
| - str(image_size_wh.min().item()) |
183 |
| - ) |
184 |
| - assert ( |
185 |
| - camera_matrix.size(1) == 3 and camera_matrix.size(2) == 3 |
186 |
| - ), "Incorrect camera matrix shape: expected 3x3 but got %dx%d" % ( |
187 |
| - camera_matrix.size(1), |
188 |
| - camera_matrix.size(2), |
189 |
| - ) |
190 |
| - assert ( |
191 |
| - R.size(1) == 3 and R.size(2) == 3 |
192 |
| - ), "Incorrect R shape: expected 3x3 but got %dx%d" % ( |
193 |
| - R.size(1), |
194 |
| - R.size(2), |
195 |
| - ) |
196 |
| - if len(tvec.size()) == 2: |
197 |
| - tvec = tvec.unsqueeze(2) |
198 |
| - assert ( |
199 |
| - tvec.size(1) == 3 and tvec.size(2) == 1 |
200 |
| - ), "Incorrect tvec shape: expected 3x1 but got %dx%d" % ( |
201 |
| - tvec.size(1), |
202 |
| - tvec.size(2), |
203 |
| - ) |
204 |
| - # Check batch size. |
205 |
| - batch_size = camera_matrix.size(0) |
206 |
| - assert R.size(0) == batch_size, "Expected R to have batch size %d. Has size %d." % ( |
207 |
| - batch_size, |
208 |
| - R.size(0), |
209 |
| - ) |
210 |
| - assert ( |
211 |
| - tvec.size(0) == batch_size |
212 |
| - ), "Expected tvec to have batch size %d. Has size %d." % ( |
213 |
| - batch_size, |
214 |
| - tvec.size(0), |
215 |
| - ) |
216 |
| - # Check image sizes. |
217 |
| - image_w = image_size_wh[0, 0] |
218 |
| - image_h = image_size_wh[0, 1] |
219 |
| - assert torch.all( |
220 |
| - image_size_wh[:, 0] == image_w |
221 |
| - ), "All images in a batch must have the same width!" |
222 |
| - assert torch.all( |
223 |
| - image_size_wh[:, 1] == image_h |
224 |
| - ), "All images in a batch must have the same height!" |
225 |
| - # Focal length. |
226 |
| - fx = camera_matrix[:, 0, 0].unsqueeze(1) |
227 |
| - fy = camera_matrix[:, 1, 1].unsqueeze(1) |
228 |
| - # Check that we introduce less than 1% error by averaging the focal lengths. |
229 |
| - fx_y = fx / fy |
230 |
| - if torch.any(fx_y > 1.01) or torch.any(fx_y < 0.99): |
231 |
| - LOGGER.warning( |
232 |
| - "Pulsar only supports a single focal lengths. For converting OpenCV " |
233 |
| - "focal lengths, we average them for x and y directions. " |
234 |
| - "The focal lengths for x and y you provided differ by more than 1%, " |
235 |
| - "which means this could introduce a noticeable error." |
236 |
| - ) |
237 |
| - f = (fx + fy) / 2 |
238 |
| - # Normalize f into normalized device coordinates. |
239 |
| - focal_length_px = f / image_w |
240 |
| - # Transfer into focal_length and sensor_width. |
241 |
| - focal_length = torch.tensor([znear - 1e-5], dtype=torch.float32, device=R.device) |
242 |
| - focal_length = focal_length[None, :].repeat(batch_size, 1) |
243 |
| - sensor_width = focal_length / focal_length_px |
244 |
| - # Principal point. |
245 |
| - cx = camera_matrix[:, 0, 2].unsqueeze(1) |
246 |
| - cy = camera_matrix[:, 1, 2].unsqueeze(1) |
247 |
| - # Transfer principal point offset into centered offset. |
248 |
| - cx = -(cx - image_w / 2) |
249 |
| - cy = cy - image_h / 2 |
250 |
| - # Concatenate to final vector. |
251 |
| - param = torch.cat([focal_length, sensor_width, cx, cy], dim=1) |
252 |
| - R_trans = R.permute(0, 2, 1) |
253 |
| - cam_pos = -torch.bmm(R_trans, tvec).squeeze(2) |
254 |
| - cam_rot = matrix_to_rotation_6d(R_trans) |
255 |
| - cam_params = torch.cat([cam_pos, cam_rot, param], dim=1) |
256 |
| - return cam_params |
| 131 | + return _pulsar_from_opencv_projection(R, tvec, camera_matrix, image_size, znear) |
257 | 132 |
|
258 | 133 |
|
259 | 134 | def pulsar_from_cameras_projection(
|
@@ -281,5 +156,4 @@ def pulsar_from_cameras_projection(
|
281 | 156 | convention `(N, 13)` (3 translation, 6 rotation, focal_length, sensor_width,
|
282 | 157 | c_x, c_y).
|
283 | 158 | """
|
284 |
| - opencv_R, opencv_T, opencv_K = opencv_from_cameras_projection(cameras, image_size) |
285 |
| - return pulsar_from_opencv_projection(opencv_R, opencv_T, opencv_K, image_size) |
| 159 | + return _pulsar_from_cameras_projection(cameras, image_size) |
0 commit comments