Skip to content

Commit

Permalink
Amend D38407094: Fisheye Camera for PyTorch3D
Browse files Browse the repository at this point in the history
Summary:
Amend FisheyeCamera by adding tests for all
combination of params and for different batch_sizes.

Reviewed By: kjchalup

Differential Revision: D39176747

fbshipit-source-id: 830d30da24beeb2f0df52db0b17a4303ed53b59c
  • Loading branch information
davidsonic authored and facebook-github-bot committed Aug 31, 2022
1 parent d4a1051 commit b0515e1
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 56 deletions.
5 changes: 2 additions & 3 deletions pytorch3d/renderer/fisheyecameras.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ def _compute_xr_yr_from_uv_distorted(
# do Newton iterations to find xr_yr
for _ in range(self.num_distortion_iters):
# compute the estimated uvDistorted
uv_distorted_est = xr_yr
uv_distorted_est = xr_yr.clone()
xr_yr_squared_norm = torch.pow(xr_yr, 2).sum(dim=-1, keepdim=True)

if self.use_tangential:
Expand Down Expand Up @@ -479,7 +479,6 @@ def _get_theta_from_norm_xr_yr(
th: angle theta (in radians) of shape (...), E.g., (P), (1, P), (M, P)
"""
sh = list(th_radial_desired.shape)
# th = th_radial_desired.clone()
th = th_radial_desired
c = torch.tensor(
[2.0 * i + 3 for i in range(self.num_radial)], device=self.device
Expand Down Expand Up @@ -552,7 +551,7 @@ def _compute_duv_distorted_dxryr(
+ 2.0 * xr_yr[..., 0] * tangential_params[..., 0]
)
else:
duv_distorted_dxryr = torch.eye(2).view(*sh, 2, 2).expand(*sh, 1, 1)
duv_distorted_dxryr = torch.eye(2).repeat(*sh, 1, 1)

if self.use_thin_prism:
temp1 = 2.0 * (
Expand Down
213 changes: 160 additions & 53 deletions tests/test_cameras.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import math
import typing
import unittest
from itertools import product

import numpy as np
import torch
Expand Down Expand Up @@ -1389,7 +1390,7 @@ def setUpAriaCase(self) -> None:
thin_prism_params,
)

def setUpBatchCameras(self) -> None:
def setUpBatchCameras(self, combination: None) -> None:
super().setUp()
focal, principal_point, p_3d = self.setUpSimpleCase()
radial_params = torch.tensor(
Expand All @@ -1412,8 +1413,12 @@ def setUpBatchCameras(self) -> None:
radial_params = torch.cat([radial_params, radial_params1], dim=0)
tangential_params = torch.cat([tangential_params, tangential_params1], dim=0)
thin_prism_params = torch.cat([thin_prism_params, thin_prism_params1], dim=0)

if combination is None:
combination = [True, True, True]
cameras = FishEyeCameras(
use_radial=combination[0],
use_tangential=combination[1],
use_thin_prism=combination[2],
focal_length=focal,
principal_point=principal_point,
radial_params=radial_params,
Expand Down Expand Up @@ -1474,21 +1479,31 @@ def test_fisheye_against_perspective_cameras(self):

def test_project_shape_broadcasts(self):
focal, principal_point, p_3d = self.setUpSimpleCase()
# test case 1:
# 1 transform with points of shape (P, 3) -> (P, 3)
# 1 transform with points of shape (1, P, 3) -> (1, P, 3)
# 1 transform with points of shape (M, P, 3) -> (M, P, 3)
points = p_3d.repeat(1, 1, 1)
cameras = FishEyeCameras(
focal_length=focal,
principal_point=principal_point,
use_radial=False,
use_tangential=False,
use_thin_prism=False,
)
uv = cameras.transform_points(p_3d)
uv_point_batch = cameras.transform_points(points)
self.assertClose(uv_point_batch, uv.repeat(1, 1, 1))
torch.set_printoptions(precision=6)
combinations = product([0, 1], repeat=3)
for combination in combinations:
cameras = FishEyeCameras(
use_radial=combination[0],
use_tangential=combination[1],
use_thin_prism=combination[2],
focal_length=focal,
principal_point=principal_point,
)
# test case 1:
# 1 transform with points of shape (P, 3) -> (P, 3)
# 1 transform with points of shape (1, P, 3) -> (1, P, 3)
# 1 transform with points of shape (M, P, 3) -> (M, P, 3)
points = p_3d.repeat(1, 1, 1)
cameras = FishEyeCameras(
focal_length=focal,
principal_point=principal_point,
use_radial=False,
use_tangential=False,
use_thin_prism=False,
)
uv = cameras.transform_points(p_3d)
uv_point_batch = cameras.transform_points(points)
self.assertClose(uv_point_batch, uv.repeat(1, 1, 1))

points = p_3d.repeat(3, 1, 1)
uv_point_batch = cameras.transform_points(points)
Expand All @@ -1497,35 +1512,105 @@ def test_project_shape_broadcasts(self):
# test case 2
# test with N transforms and points of shape (P, 3) -> (N, P, 3)
# test with N transforms and points of shape (1, P, 3) -> (N, P, 3)

# first camera transform params
cameras = self.setUpBatchCameras()
torch.set_printoptions(sci_mode=False)
p_3d = torch.tensor(
[
[2.0, 3.0, 1.0],
[2.0, 3.0, 1.0],
[3.0, 2.0, 1.0],
]
)
expected_res = torch.tensor(
[
[
[493.0993, 499.6489, 1.0],
[493.0993, 499.6489, 1.0],
[579.6489, 413.0993, 1.0],
[
[800.000000, 960.000000, 1.000000],
[1040.000000, 720.000000, 1.000000],
],
[
[1929.862549, 2533.643311, 1.000000],
[2538.788086, 1924.717773, 1.000000],
],
],
[
[
[800.000000, 960.000000, 1.000000],
[1040.000000, 720.000000, 1.000000],
],
[
[1927.272095, 2524.220459, 1.000000],
[2536.197754, 1915.295166, 1.000000],
],
],
[
[
[800.000000, 960.000000, 1.000000],
[1040.000000, 720.000000, 1.000000],
],
[
[1930.050293, 2538.434814, 1.000000],
[2537.956543, 1927.569092, 1.000000],
],
],
[
[
[800.000000, 960.000000, 1.000000],
[1040.000000, 720.000000, 1.000000],
],
[
[1927.459839, 2529.011963, 1.000000],
[2535.366211, 1918.146484, 1.000000],
],
],
[
[
[493.099304, 499.648926, 1.000000],
[579.648926, 413.099304, 1.000000],
],
[
[1662.673950, 2132.860352, 1.000000],
[2138.005127, 1657.529053, 1.000000],
],
],
[
[
[493.099304, 499.648926, 1.000000],
[579.648926, 413.099304, 1.000000],
],
[
[1660.083496, 2123.437744, 1.000000],
[2135.414795, 1648.106445, 1.000000],
],
],
[
[
[493.099304, 499.648926, 1.000000],
[579.648926, 413.099304, 1.000000],
],
[
[1662.861816, 2137.651855, 1.000000],
[2137.173828, 1660.380371, 1.000000],
],
],
[
[1660.2700, 2128.2273, 1.0],
[1660.2700, 2128.2273, 1.0],
[2134.5815, 1650.9565, 1.0],
[
[493.099304, 499.648926, 1.000000],
[579.648926, 413.099304, 1.000000],
],
[
[1660.271240, 2128.229248, 1.000000],
[2134.583496, 1650.957764, 1.000000],
],
],
]
)
uv_point_batch = cameras.transform_points(p_3d)
self.assertClose(uv_point_batch, expected_res)
combinations = product([0, 1], repeat=3)
for i, combination in enumerate(combinations):
cameras = self.setUpBatchCameras(combination)
uv_point_batch = cameras.transform_points(p_3d)
self.assertClose(uv_point_batch, expected_res[i])

uv_point_batch = cameras.transform_points(p_3d.repeat(1, 1, 1))
self.assertClose(uv_point_batch, expected_res)
uv_point_batch = cameras.transform_points(p_3d.repeat(1, 1, 1))
self.assertClose(uv_point_batch, expected_res[i].repeat(1, 1, 1))

def test_cuda(self):
"""
Expand Down Expand Up @@ -1573,42 +1658,64 @@ def test_unproject_shape_broadcasts(self):
rep_3d = cameras.unproject_points(xy_depth)
expected_res = torch.tensor(
[
[3.0000, 2.0000, 1.0000],
[0.666667, 0.833333, 1.0000],
],
)
self.assertClose(rep_3d, expected_res)

rep_3d = cameras.unproject_points(xy_depth.repeat(3, 1, 1))
self.assertClose(rep_3d, expected_res.repeat(3, 1, 1))

# test case 2:
# N transforms with points of (P, 3) -> (N, P, 3)
# N transforms with points of (1, P, 3) -> (N, P, 3)
cameras = FishEyeCameras(
focal_length=focal.repeat(2, 1),
principal_point=principal_point.repeat(2, 1),
radial_params=radial_params.repeat(2, 1),
tangential_params=tangential_params.repeat(2, 1),
thin_prism_params=thin_prism_params.repeat(2, 1),
[[2.999442, 1.990583, 1.000000], [0.666728, 0.833142, 1.000000]],
[[2.997338, 2.005411, 1.000000], [0.666859, 0.834456, 1.000000]],
[[3.002090, 1.985229, 1.000000], [0.666537, 0.832025, 1.000000]],
[[2.999999, 2.000000, 1.000000], [0.666667, 0.833333, 1.000000]],
[[2.999442, 1.990583, 1.000000], [0.666728, 0.833142, 1.000000]],
[[2.997338, 2.005411, 1.000000], [0.666859, 0.834456, 1.000000]],
[[3.002090, 1.985229, 1.000000], [0.666537, 0.832025, 1.000000]],
[[2.999999, 2.000000, 1.000000], [0.666667, 0.833333, 1.000000]],
]
)
rep_3d = cameras.unproject_points(xy_depth)
self.assertClose(rep_3d, expected_res.repeat(2, 1, 1))
torch.set_printoptions(precision=6)
combinations = product([0, 1], repeat=3)
for i, combination in enumerate(combinations):
cameras = FishEyeCameras(
use_radial=combination[0],
use_tangential=combination[1],
use_thin_prism=combination[2],
focal_length=focal,
principal_point=principal_point,
radial_params=radial_params,
tangential_params=tangential_params,
thin_prism_params=thin_prism_params,
)
rep_3d = cameras.unproject_points(xy_depth)
self.assertClose(rep_3d, expected_res[i])
rep_3d = cameras.unproject_points(xy_depth.repeat(3, 1, 1))
self.assertClose(rep_3d, expected_res[i].repeat(3, 1, 1))

# test case 2:
# N transforms with points of (P, 3) -> (N, P, 3)
# N transforms with points of (1, P, 3) -> (N, P, 3)
cameras = FishEyeCameras(
use_radial=combination[0],
use_tangential=combination[1],
use_thin_prism=combination[2],
focal_length=focal.repeat(2, 1),
principal_point=principal_point.repeat(2, 1),
radial_params=radial_params.repeat(2, 1),
tangential_params=tangential_params.repeat(2, 1),
thin_prism_params=thin_prism_params.repeat(2, 1),
)
rep_3d = cameras.unproject_points(xy_depth)
self.assertClose(rep_3d, expected_res[i].repeat(2, 1, 1))

def test_unhandled_shape(self):
"""
Test error handling when shape of transforms
and points are not expected.
"""
cameras = self.setUpBatchCameras()
cameras = self.setUpBatchCameras(None)
points = torch.rand(3, 3, 1)
with self.assertRaises(ValueError):
cameras.transform_points(points)

def test_getitem(self):
# Check get item returns an instance of the same class
# with all the same keys
cam = self.setUpBatchCameras()
cam = self.setUpBatchCameras(None)
c0 = cam[0]
self.assertTrue(isinstance(c0, FishEyeCameras))
self.assertEqual(cam.__dict__.keys(), c0.__dict__.keys())

0 comments on commit b0515e1

Please sign in to comment.