-
Notifications
You must be signed in to change notification settings - Fork 534
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add spherical sampling, conversion between spherical and cartesian (#661
) * add spherical sampling, conversion between spherical and cartesian Signed-off-by: Clement Fuji Tsang <cfujitsang@nvidia.com> * add reference to kaolin.ops.coords in doc Signed-off-by: Clement Fuji Tsang <cfujitsang@nvidia.com> Signed-off-by: Clement Fuji Tsang <cfujitsang@nvidia.com>
- Loading branch information
Showing
9 changed files
with
242 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. | ||
# All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from __future__ import division | ||
|
||
import torch | ||
|
||
def spherical2cartesian(azimuth, elevation, distance=None): | ||
"""Convert spherical coordinates to cartesian. | ||
Assuming X toward camera, Z-up and Y-right. | ||
Args: | ||
azimuth (torch.Tensor): azimuth in radianss. | ||
elevation (torch.Tensor): elevation in radians. | ||
distance (torch.Tensor or float, optional): distance. Default: 1. | ||
Returns: | ||
(torch.Tensor, torch.Tensor, torch.Tensor): | ||
x, y, z, of same shape and dtype than inputs. | ||
""" | ||
if distance is None: | ||
z = torch.sin(elevation) | ||
temp = torch.cos(elevation) | ||
else: | ||
z = torch.sin(elevation) * distance | ||
temp = torch.cos(elevation) * distance | ||
x = torch.cos(azimuth) * temp | ||
y = torch.sin(azimuth) * temp | ||
return x, y, z | ||
|
||
def cartesian2spherical(x, y, z): | ||
"""Convert cartersian coordinates to spherical in radians. | ||
Assuming X toward camera, Z-up and Y-right. | ||
Args: | ||
x (torch.Tensor): X components of the coordinates. | ||
y (torch.Tensor): Y components of the coordinates. | ||
z (torch.Tensor): Z components of the coordinates. | ||
Returns: | ||
(torch.Tensor, torch.Tensor, torch.Tensor): | ||
azimuth, elevation, distance, of same shape and dtype than inputs. | ||
""" | ||
distance = torch.sqrt(x ** 2 + y ** 2 + z ** 2) | ||
elevation = torch.asin(z / distance) | ||
azimuth = torch.atan2(y, x) | ||
return azimuth, elevation, distance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. | ||
# All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import pytest | ||
import math | ||
import torch | ||
|
||
from kaolin.utils.testing import FLOAT_TYPES, check_tensor | ||
from kaolin.ops.coords import cartesian2spherical, spherical2cartesian | ||
|
||
@pytest.mark.parametrize('device, dtype', FLOAT_TYPES) | ||
class TestCartesian2Spherical: | ||
@pytest.fixture(autouse=True) | ||
def coords(self, device, dtype): | ||
coords = torch.rand((11, 7, 3), device=device, dtype=dtype) * 10. - 5. | ||
return { | ||
'x': coords[..., 0], | ||
'y': coords[..., 1], | ||
'z': coords[..., 2] | ||
} | ||
|
||
def test_cartesian2spherical(self, coords, dtype): | ||
x = coords['x'] | ||
y = coords['y'] | ||
z = coords['z'] | ||
|
||
azimuth, elevation, distance = cartesian2spherical(x, y, z) | ||
# This is pretty much how it is currently implemented in the function | ||
# but this is very simple | ||
expected_distance = torch.sqrt( | ||
x ** 2 + y ** 2 + z ** 2) | ||
expected_elevation = torch.asin(z / distance) | ||
expected_azimuth = torch.atan2(y, z) | ||
assert torch.allclose(azimuth, expected_azimuth) | ||
assert torch.allclose(elevation, expected_elevation) | ||
assert torch.allclose(distance, expected_distance) | ||
|
||
def test_cartesian2spherical2cartesian(self, coords): | ||
x = coords['x'] | ||
y = coords['y'] | ||
z = coords['z'] | ||
|
||
azimuth, elevation, distance = cartesian2spherical(x, y, z) | ||
out_x, out_y, out_z = spherical2cartesian(azimuth, elevation, distance) | ||
assert torch.allclose(x, out_x) | ||
assert torch.allclose(y, out_y) | ||
assert torch.allclose(z, out_z) | ||
|
||
@pytest.mark.parametrize('device, dtype', FLOAT_TYPES) | ||
class TestCartesian2Spherical: | ||
@pytest.fixture(autouse=True) | ||
def coords(self, device, dtype): | ||
# Not uniform but good enough | ||
return { | ||
'azimuth': (torch.rand((11, 7), device=device, dtype=dtype) * 2. - 1.) * math.pi, | ||
'elevation': (torch.rand((11, 7), device=device, dtype=dtype) - 0.5) * math.pi, | ||
'distance': torch.rand((11, 7), device=device, dtype=dtype) * 10. + 0.1 | ||
} | ||
|
||
def test_spherical2cartesian(self, coords, dtype): | ||
azimuth = coords['azimuth'] | ||
elevation = coords['elevation'] | ||
distance = coords['distance'] | ||
|
||
x, y, z = spherical2cartesian(azimuth, elevation, distance) | ||
# This is pretty much how it is currently implemented in the function | ||
# but this is very simple | ||
expected_z = torch.sin(elevation) * distance | ||
temp = torch.cos(elevation) * distance | ||
expected_x = torch.cos(azimuth) * temp | ||
expected_y = torch.sin(azimuth) * temp | ||
assert torch.equal(x, expected_x) | ||
assert torch.equal(y, expected_y) | ||
assert torch.equal(z, expected_z) | ||
|
||
def test_spherical2cartesian2spherical(self, coords): | ||
azimuth = coords['azimuth'] | ||
elevation = coords['elevation'] | ||
distance = coords['distance'] | ||
|
||
x, y, z = spherical2cartesian(azimuth, elevation, distance) | ||
out_azimuth, out_elevation, out_distance = cartesian2spherical( | ||
x, y, z) | ||
assert torch.allclose(azimuth, out_azimuth, rtol=1e-3, atol=1e-3) | ||
assert torch.allclose(elevation, out_elevation, rtol=1e-1, atol=1e-1) | ||
assert torch.allclose(distance, out_distance, rtol=1e-3, atol=1e-3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters