Skip to content

Commit 8006842

Browse files
davnov134facebook-github-bot
authored andcommitted
Conversion from OpenCV cameras
Summary: Implements a conversion function between OpenCV and PyTorch3D cameras. Reviewed By: patricklabatut Differential Revision: D28992470 fbshipit-source-id: dbcc9f213ec293c2f6938261c704aea09aad3c90
1 parent b2ac265 commit 8006842

File tree

4 files changed

+1450
-0
lines changed

4 files changed

+1450
-0
lines changed

pytorch3d/utils/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
22

3+
from .camera_conversions import cameras_from_opencv_projection
34
from .ico_sphere import ico_sphere
45
from .torus import torus
56

pytorch3d/utils/camera_conversions.py

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import torch
2+
3+
from ..renderer import PerspectiveCameras
4+
from ..transforms import so3_exponential_map
5+
6+
7+
def cameras_from_opencv_projection(
8+
rvec: torch.Tensor,
9+
tvec: torch.Tensor,
10+
camera_matrix: torch.Tensor,
11+
image_size: torch.Tensor,
12+
) -> PerspectiveCameras:
13+
"""
14+
Converts a batch of OpenCV-conventioned cameras parametrized with the
15+
axis-angle rotation vectors `rvec`, translation vectors `tvec`, and the camera
16+
calibration matrices `camera_matrix` to `PerspectiveCameras` in PyTorch3D
17+
convention.
18+
19+
More specifically, the conversion is carried out such that a projection
20+
of a 3D shape to the OpenCV-conventioned screen of size `image_size` results
21+
in the same image as a projection with the corresponding PyTorch3D camera
22+
to the NDC screen convention of PyTorch3D.
23+
24+
More specifically, the OpenCV convention projects points to the OpenCV screen
25+
space as follows:
26+
```
27+
x_screen_opencv = camera_matrix @ (exp(rvec) @ x_world + tvec)
28+
```
29+
followed by the homogenization of `x_screen_opencv`.
30+
31+
Note:
32+
The parameters `rvec, tvec, camera_matrix` correspond e.g. to the inputs
33+
of `cv2.projectPoints`, or to the ouputs of `cv2.calibrateCamera`.
34+
35+
Args:
36+
rvec: A batch of axis-angle rotation vectors of shape `(N, 3)`.
37+
tvec: A batch of translation vectors of shape `(N, 3)`.
38+
camera_matrix: A batch of camera calibration matrices of shape `(N, 3, 3)`.
39+
image_size: A tensor of shape `(N, 2)` containing the sizes of the images
40+
(height, width) attached to each camera.
41+
42+
Returns:
43+
cameras_pytorch3d: A batch of `N` cameras in the PyTorch3D convention.
44+
"""
45+
46+
R = so3_exponential_map(rvec)
47+
focal_length = torch.stack([camera_matrix[:, 0, 0], camera_matrix[:, 1, 1]], dim=-1)
48+
principal_point = camera_matrix[:, :2, 2]
49+
50+
# Retype the image_size correctly and flip to width, height.
51+
image_size_wh = image_size.to(R).flip(dims=(1,))
52+
53+
# Get the PyTorch3D focal length and principal point.
54+
focal_pytorch3d = focal_length / (0.5 * image_size_wh)
55+
p0_pytorch3d = -(principal_point / (0.5 * image_size_wh) - 1)
56+
57+
# For R, T we flip x, y axes (opencv screen space has an opposite
58+
# orientation of screen axes).
59+
# We also transpose R (opencv multiplies points from the opposite=left side).
60+
R_pytorch3d = R.permute(0, 2, 1)
61+
T_pytorch3d = tvec.clone()
62+
R_pytorch3d[:, :, :2] *= -1
63+
T_pytorch3d[:, :2] *= -1
64+
65+
return PerspectiveCameras(
66+
R=R_pytorch3d,
67+
T=T_pytorch3d,
68+
focal_length=focal_pytorch3d,
69+
principal_point=p0_pytorch3d,
70+
)

0 commit comments

Comments
 (0)