Repository: kornia/kornia

Issue:
Add `depth_from_disparity` / `disparity_from_depth`
## 🚀 Feature

Implement a simple utility function to compute depth from/to disparity

```python
def depth_from_disparity(disparity: Tensor, baseline: Union[float, Tensor], focal: Union[float, Tensor]) -> Tensor:
    # TODO: add some checks
    return baseline * focal / disparity
```

```python
def disparity_from_depth(depth: Tensor, baseline: Union[float, Tensor], focal: Union[float, Tensor]) -> Tensor:
    # TODO: add some checks
    return baseline * focal / depth
```

______________________________________________________________________

#### Consider also to contribute to Kornia universe projects :)

<sub>

- [**Tutorials**](https://github.com/kornia/tutorials): our repository containing the tutorials.

</sub>



Discussion:

Resolving patch:
diff --git a/kornia/geometry/depth.py b/kornia/geometry/depth.py
--- a/kornia/geometry/depth.py
+++ b/kornia/geometry/depth.py
@@ -6,6 +6,7 @@
 
 from kornia.core import Module, Tensor, concatenate, tensor
 from kornia.filters.sobel import spatial_gradient
+from kornia.testing import KORNIA_CHECK, KORNIA_CHECK_IS_TENSOR, KORNIA_CHECK_SHAPE
 from kornia.utils import create_meshgrid
 
 from .camera import PinholeCamera, cam2pixel, pixel2cam, project_points, unproject_points
@@ -365,3 +366,40 @@ def depth_warp(
     warper = DepthWarper(pinhole_dst, height, width, align_corners=align_corners)
     warper.compute_projection_matrix(pinhole_src)
     return warper(depth_src, patch_dst)
+
+
+def depth_from_disparity(disparity: Tensor, baseline: Union[float, Tensor], focal: Union[float, Tensor]) -> Tensor:
+    """Computes depth from disparity.
+
+    Args:
+        disparity: Disparity tensor of shape :math:`(*, H, W)`.
+        baseline: float/tensor containing the distance between the two lenses.
+        focal: float/tensor containing the focal length.
+
+    Return:
+        Depth map of the shape :math:`(*, H, W)`.
+
+    Example:
+        >>> disparity = torch.rand(4, 1, 4, 4)
+        >>> baseline = torch.rand(1)
+        >>> focal = torch.rand(1)
+        >>> depth_from_disparity(disparity, baseline, focal).shape
+        torch.Size([4, 1, 4, 4])
+    """
+    KORNIA_CHECK_IS_TENSOR(disparity, f"Input disparity type is not a Tensor. Got {type(disparity)}.")
+    KORNIA_CHECK_SHAPE(disparity, ["*", "H", "W"])
+    KORNIA_CHECK(
+        isinstance(baseline, (float, Tensor)),
+        f"Input baseline should be either a float or Tensor. " f"Got {type(baseline)}",
+    )
+    KORNIA_CHECK(
+        isinstance(focal, (float, Tensor)), f"Input focal should be either a float or Tensor. " f"Got {type(focal)}"
+    )
+
+    if isinstance(baseline, Tensor):
+        KORNIA_CHECK_SHAPE(baseline, ["1"])
+
+    if isinstance(focal, Tensor):
+        KORNIA_CHECK_SHAPE(focal, ["1"])
+
+    return baseline * focal / disparity


Test patch:
diff --git a/test/geometry/test_depth.py b/test/geometry/test_depth.py
--- a/test/geometry/test_depth.py
+++ b/test/geometry/test_depth.py
@@ -329,3 +329,68 @@ def test_gradcheck(self, device, dtype):
             raise_exception=True,
             fast_mode=True,
         )
+
+
+class TestDepthFromDisparity:
+    def test_smoke(self, device, dtype):
+        disparity = 2 * torch.tensor(
+            [[[[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]]], device=device, dtype=dtype
+        )
+
+        baseline = torch.tensor([1.0], device=device, dtype=dtype)
+        focal = torch.tensor([1.0], device=device, dtype=dtype)
+
+        depth_expected = torch.tensor(
+            [
+                [
+                    [
+                        [0.5000, 0.5000, 0.5000],
+                        [0.5000, 0.5000, 0.5000],
+                        [0.5000, 0.5000, 0.5000],
+                        [0.5000, 0.5000, 0.5000],
+                    ]
+                ]
+            ],
+            device=device,
+            dtype=dtype,
+        )
+
+        depth = kornia.geometry.depth.depth_from_disparity(disparity, baseline, focal)
+        assert_close(depth, depth_expected, rtol=1e-3, atol=1e-3)
+
+    @pytest.mark.parametrize("batch_size", [2, 4, 5])
+    def test_cardinality(self, batch_size, device, dtype):
+        disparity = torch.rand(batch_size, 1, 3, 4, device=device, dtype=dtype)
+        baseline = torch.rand(1, device=device, dtype=dtype)
+        focal = torch.rand(1, device=device, dtype=dtype)
+
+        points3d = kornia.geometry.depth.depth_from_disparity(disparity, baseline, focal)
+        assert points3d.shape == (batch_size, 1, 3, 4)
+
+    @pytest.mark.parametrize("shape", [(1, 1, 3, 4), (4, 1, 3, 4), (4, 3, 4), (1, 3, 4), (3, 4)])
+    def test_shapes(self, shape, device, dtype):
+        disparity = torch.randn(shape, device=device, dtype=dtype)
+        baseline = torch.rand(1, device=device, dtype=dtype)
+        focal = torch.rand(1, device=device, dtype=dtype)
+
+        points3d = kornia.geometry.depth.depth_from_disparity(disparity, baseline, focal)
+        assert points3d.shape == shape
+
+    def test_gradcheck(self, device):
+        # generate input data
+        disparity = torch.rand(1, 1, 3, 4, device=device)
+        disparity = utils.tensor_to_gradcheck_var(disparity)  # to var
+
+        baseline = torch.rand(1, device=device)
+        baseline = utils.tensor_to_gradcheck_var(baseline)  # to var
+
+        focal = torch.rand(1, device=device)
+        focal = utils.tensor_to_gradcheck_var(focal)  # to var
+
+        # evaluate function gradient
+        assert gradcheck(
+            kornia.geometry.depth.depth_from_disparity,
+            (disparity, baseline, focal),
+            raise_exception=True,
+            fast_mode=True,
+        )