ronantakizawa/codereview-bench huggingface dataset:
Repository: Genesis-Embodied-AI/Genesis
File: genesis/engine/solvers/base_solver.py (Python)

Code before:
from typing import TYPE_CHECKING
import numpy as np
import taichi as ti
import torch
from genesis.utils.misc import ti_field_to_torch

import genesis as gs
from genesis.engine.entities.base_entity import Entity
from genesis.repr_base import RBC


if TYPE_CHECKING:
    from genesis.engine.scene import Scene
    from genesis.engine.simulator import Simulator


class Solver(RBC):
    def __init__(self, scene: "Scene", sim: "Simulator", options):
        self._uid = gs.UID()
        self._sim = sim
        self._scene = scene
        self._dt: float = options.dt
        self._substep_dt: float = options.dt / sim.substeps
        self._gravity = None
        self._entities: list[Entity] = gs.List()

        # force fields
        self._ffs = list()

    def _add_force_field(self, force_field):
        self._ffs.append(force_field)


    def build(self, B: int):
        self._B = B
        g_np = np.asarray(self._sim._gravity)
        g_np = np.repeat(g_np[None], B, axis=0)
        self._gravity = ti.Vector.field(3, dtype=gs.ti_float, shape=B)
        self._gravity.from_numpy(g_np)

    def set_gravity(self, gravity, envs_idx=None):
        if self._gravity is None:
            return
        if envs_idx is None:
            self._gravity.copy_from(gravity)
        else:
            self._gravity[envs_idx] = gravity


Review comment (suggestion):
You need to keep track of the solver-specific gravity:
```python
self._init_gravity = getattr(options, "gravity")
```

Code after:
from typing import TYPE_CHECKING
import numpy as np
import taichi as ti
import torch
from genesis.utils.misc import ti_field_to_torch

import genesis as gs
from genesis.engine.entities.base_entity import Entity
from genesis.repr_base import RBC


if TYPE_CHECKING:
    from genesis.engine.scene import Scene
    from genesis.engine.simulator import Simulator


class Solver(RBC):
    def __init__(self, scene: "Scene", sim: "Simulator", options):
        self._uid = gs.UID()
        self._sim = sim
        self._scene = scene
        self._dt: float = options.dt
        self._substep_dt: float = options.dt / sim.substeps
        self._init_gravity = getattr(options, "gravity", None)
        self._gravity = None
        self._entities: list[Entity] = gs.List()

        # force fields
        self._ffs = list()

    def _add_force_field(self, force_field):
        self._ffs.append(force_field)

    def build(self):
        self._B = self._sim._B
        if self._init_gravity is not None:
            g_np = np.asarray(self._init_gravity, dtype=gs.np_float)
            g_np = np.repeat(g_np[None], self._B, axis=0)
            self._gravity = ti.Vector.field(3, dtype=gs.ti_float, shape=self._B)
            self._gravity.from_numpy(g_np)

    @gs.assert_built
    def set_gravity(self, gravity, envs_idx=None):
        if self._gravity is None:
            return
        g = np.asarray(gravity, dtype=gs.np_float)
        if envs_idx is None:
            if g.ndim == 1:
Repository: Genesis-Embodied-AI/Genesis
File: tests/test_rigid_physics.py (Python)

Code before:
        show_viewer=show_viewer,
        sim_options=gs.options.SimOptions(
            dt=0.002,
            substeps=1,
        ),
    )
    drone_ref = scene_ref.add_entity(
        morph=gs.morphs.Drone(
            file="urdf/drones/cf2x.urdf",
            pos=(0, 0, 1.0),
        ),
    )
    scene_ref.build()

    for _ in range(2500):
        drone_ref.set_propellels_rpm([base_rpm, base_rpm, base_rpm, base_rpm])
        scene_ref.step()

    pos_ref = drone_ref.get_dofs_position()

    scene_test = gs.Scene(
        show_viewer=show_viewer,
        sim_options=gs.options.SimOptions(
            dt=0.01,
            substeps=5,
        ),
    )
    drone_test = scene_test.add_entity(
        morph=gs.morphs.Drone(
            file="urdf/drones/cf2x.urdf",
            pos=(0, 0, 1.0),
        ),
    )
    scene_test.build()

    for _ in range(500):
        drone_test.set_propellels_rpm([base_rpm, base_rpm, base_rpm, base_rpm])
        scene_test.step()

    pos_test = drone_test.get_dofs_position()

    assert_allclose(pos_ref, pos_test, tol=tol)


@pytest.mark.required
@pytest.mark.parametrize("backend", [gs.cpu])
def test_drone_advanced(show_viewer):
    scene = gs.Scene(
        sim_options=gs.options.SimOptions(
            dt=0.005,
        ),

Review comment (suggestion):
Just do:
```python
scene = gs.Scene(
       show_viewer=show_viewer,
    )
```

Code after:
    scene = gs.Scene(
        show_viewer=show_viewer,
    )
    hand = scene.add_entity(
        gs.morphs.URDF(
            file="urdf/panda_bullet/hand.urdf",
            fixed=True,
        ),
    )
    scene.build()
    assert scene.rigid_solver.n_equalities == 1

    qvel = scene.rigid_solver.dofs_state.vel.to_numpy()
    qvel[-1] = 1
    scene.rigid_solver.dofs_state.vel.from_numpy(qvel)
    for i in range(200):
        scene.step()

    gs_qpos = scene.rigid_solver.qpos.to_numpy()[:, 0]
    assert_allclose(gs_qpos[-1], gs_qpos[-2], tol=tol)


@pytest.mark.required
@pytest.mark.parametrize("backend", [gs.cpu])
def test_gravity(show_viewer, tol):
    scene = gs.Scene(
        show_viewer=show_viewer,
    )

    sphere = scene.add_entity(gs.morphs.Sphere())
    scene.build(n_envs=2)

    scene.sim.set_gravity(torch.tensor([0.0, 0.0, -9.8]), envs_idx=0)
    scene.sim.set_gravity(torch.tensor([0.0, 0.0, 9.8]), envs_idx=1)

    for _ in range(200):
        scene.step()

    first_pos = sphere.get_dofs_position()[0, 2]
    second_pos = sphere.get_dofs_position()[1, 2]

    assert_allclose(first_pos * -1, second_pos, tol=tol)


@pytest.mark.required
@pytest.mark.parametrize("backend", [gs.cpu])
def test_scene_saver_franka(show_viewer, tol):
    scene1 = gs.Scene(show_viewer=show_viewer)
    franka1 = scene1.add_entity(
        gs.morphs.MJCF(file="xml/franka_emika_panda/panda.xml"),
    )
Repository: Genesis-Embodied-AI/Genesis
File: tests/test_mesh.py (Python)

Code before:
        check_gs_textures(
            gs_glb_material.metallic_texture, gs_usd_material.metallic_texture, 0.0, material_name, "metallic"
        )
        check_gs_textures(gs_glb_material.normal_texture, gs_usd_material.normal_texture, 0.0, material_name, "normal")
        check_gs_textures(
            gs_glb_material.emissive_texture, gs_usd_material.emissive_texture, 0.0, material_name, "emissive"
        )


@pytest.mark.required
def test_urdf_with_existing_glb():
    assets = Path(gs.utils.get_assets_dir())
    glb_path = assets / "usd" / "sneaker_airforce.glb"

    tmp_path = Path(__file__).parent
    urdf_path = tmp_path / "model.urdf"
    urdf_path.write_text(
        f"""<robot name="shoe">
               <link name="base">
                 <visual>
                   <geometry><mesh filename="{glb_path}"/></geometry>
                 </visual>
               </link>
             </robot>"""
    )
    scene = gs.Scene(show_viewer=False)
    scene.build()
    scene.step()


Review comment (suggestion):
```python
scene = gs.Scene(
    show_viewer= show_viewer,
    show_FPS=False,
)
```

Code after:
            gs_glb_material.metallic_texture, gs_usd_material.metallic_texture, 0.0, material_name, "metallic"
        )
        check_gs_textures(gs_glb_material.normal_texture, gs_usd_material.normal_texture, 0.0, material_name, "normal")
        check_gs_textures(
            gs_glb_material.emissive_texture, gs_usd_material.emissive_texture, 0.0, material_name, "emissive"
        )


@pytest.mark.required
def test_urdf_with_existing_glb(tmp_path, show_viewer):
    assets = Path(gs.utils.get_assets_dir())
    glb_path = assets / "usd" / "sneaker_airforce.glb"
    urdf_path = tmp_path / "model.urdf"
    urdf_path.write_text(
        f"""<robot name="shoe">
              <link name="base">
                <visual>
                  <geometry><mesh filename="{glb_path}"/></geometry>
                </visual>
              </link>
            </robot>
         """
    )
    scene = gs.Scene(
        show_viewer=show_viewer,
        show_FPS=False,
    )
    scene.build()
    scene.step()


@pytest.mark.required
@pytest.mark.parametrize(
    "n_channels, float_type",
    [
        (1, np.float32),  # grayscale → H×W
        (2, np.float64),  # L+A       → H×W×2
    ],
)
def test_urdf_with_float_texture_glb(tmp_path, show_viewer, n_channels, float_type):
    vertices = np.array(
        [[-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.5, 0.5, 0.0], [-0.5, 0.5, 0.0]],
        dtype=np.float32,
    )
    faces = np.array([[0, 1, 2], [0, 2, 3]], dtype=np.uint32)

    mesh = trimesh.Trimesh(vertices, faces, process=False)

    H = W = 16
    if n_channels == 1:
        img = np.random.rand(H, W).astype(float_type)
Repository: Genesis-Embodied-AI/Genesis
File: genesis/ext/pyrender/interaction/vec3.py (Python)

Code before:
from dataclasses import dataclass
from typing import Union

import numpy as np
from numpy.typing import NDArray

from genesis.utils.misc import tensor_to_array

# If not needing runtime checks, we can just use annotated types:
# Vec3 = Annotated[npt.NDArray[np.float32], (3,)]
# Aabb = Annotated[npt.NDArray[np.float32], (2, 3)]

_is_torch_imported: bool = False

def _ensure_torch_imported() -> None:
    global _is_torch_imported
    if not _is_torch_imported:
        _is_torch_imported = True
        global gs
        import genesis as gs
        global torch
        import torch


class Vec3:
    """
    Use this wrapper around np.array if you want to ensure adherence to float32 arithmethic
    with runtime checks, and avoid hidden and costly conversions between float32 and float64.

    This also makes vector dimensionality explicit for linting and static analysis.
    """
    v: NDArray[np.float32]

    def __init__(self, v: NDArray[np.float32]):
        assert v.shape == (3,), f"Vec3 must be initialized with a 3-element array, got {v.shape}"
        assert v.dtype == np.float32, f"Vec3 must be initialized with a float32 array, got {v.dtype}"
        self.v = v

    def __add__(self, other: 'Vec3') -> 'Vec3':

Review comment (suggestion):
You don't need to do this I think, you may just call `import torch` or `import genesis as gs`, it will be crazy fast if already imported before.

```python
In [19]: %timeit import torch
48.2 ns ± 0.452 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
```

I doubt you are chasing 50ns for now :p 


Code after:
from dataclasses import dataclass
from typing import Union

import numpy as np
from numpy.typing import NDArray

from genesis.utils.misc import tensor_to_array

# If not needing runtime checks, we can just use annotated types:
# Vec3 = Annotated[npt.NDArray[np.float32], (3,)]
# Aabb = Annotated[npt.NDArray[np.float32], (2, 3)]


def _ensure_torch_imported() -> None:
    global gs
    import genesis as gs
    global torch
    import torch


class Vec3:
    """
    Use this wrapper around np.array if you want to ensure adherence to float32 arithmethic
    with runtime checks, and avoid hidden and costly conversions between float32 and float64.

    This also makes vector dimensionality explicit for linting and static analysis.
    """
    v: NDArray[np.float32]

    def __init__(self, v: NDArray[np.float32]):
        assert v.shape == (3,), f"Vec3 must be initialized with a 3-element array, got {v.shape}"
        assert v.dtype == np.float32, f"Vec3 must be initialized with a float32 array, got {v.dtype}"
        self.v = v

    def __add__(self, other: 'Vec3') -> 'Vec3':
        return Vec3(self.v + other.v)

    def __sub__(self, other: 'Vec3') -> 'Vec3':
        return Vec3(self.v - other.v)
Repository: Genesis-Embodied-AI/Genesis
File: genesis/ext/pyrender/interaction/aabb.py (Python)

Code before:

    def __repr__(self) -> str:
        return f"AABB: Min({self.min.x}, {self.min.y}, {self.min.z}) Max({self.max.x}, {self.max.y}, {self.max.z})"

    @classmethod
    def from_min_max(cls, min: Vec3, max: Vec3) -> 'AABB':
        bounds = np.stack((min.v, max.v))
        return cls(bounds)

    @classmethod
    def from_center_and_size(cls, center: Vec3, size: Vec3) -> 'AABB':
        min = center - 0.5 * size
        max = center + 0.5 * size
        bounds = np.stack((min.v, max.v))
        return cls(bounds)


class OBB(AABB):
    pose: Pose

    def __init__(self, v: NDArray[np.float32], pose: Pose):
        super().__init__(v)
        self.pose = pose

    def raycast(self, ray: Ray) -> RayHit:
        inv_pose = self.pose.get_inverse()
        origin2 = inv_pose.transform_point(ray.origin)
        direction2 = inv_pose.transform_direction(ray.direction)
        ray2 = Ray(origin2, direction2)
        ray_hit = super().raycast(ray2)
        if ray_hit.is_hit:
            ray_hit.position = self.pose.transform_point(ray_hit.position)
            ray_hit.normal = self.pose.transform_direction(ray_hit.normal)
        return ray_hit

    def __repr__(self) -> str:
        return f"OBB: Min({self.min.x}, {self.min.y}, {self.min.z}) Max({self.max.x}, {self.max.y}, {self.max.z}) " \
            + f"Pose: {self.pose}"

    @classmethod
    def from_center_and_size(cls, size: Vec3, pose: Pose) -> 'OBB':
        min = - 0.5 * size
        max = + 0.5 * size
        bounds = np.stack((min.v, max.v))
        return cls(bounds, pose)


Review comment (performance):
Do not compute inverse explicit. This is slow. You should rather implement `inv_transform_point`, `inv_transform_direction`

Code after:
        hit_pos = ray.origin + ray.direction * enter
        return RayHit(enter, hit_pos, normal)

    def __repr__(self) -> str:
        return f"AABB: Min({self.min.x}, {self.min.y}, {self.min.z}) Max({self.max.x}, {self.max.y}, {self.max.z})"

    @classmethod
    def from_min_max(cls, min: Vec3, max: Vec3) -> 'AABB':
        bounds = np.stack((min.v, max.v), axis=0)
        return cls(bounds)

    @classmethod
    def from_center_and_half_extents(cls, center: Vec3, half_extents: Vec3) -> 'AABB':
        min = center - half_extents
        max = center + half_extents
        bounds = np.stack((min.v, max.v), axis=0)
        return cls(bounds)


@dataclass
class OBB():
    pose: Pose
    half_extents: Vec3

    def raycast(self, ray: Ray) -> RayHit:
        origin2 = self.pose.inverse_transform_point(ray.origin)
        direction2 = self.pose.inverse_transform_direction(ray.direction)
        ray2 = Ray(origin2, direction2)
        aabb = AABB.from_center_and_half_extents(Vec3.zero(), self.half_extents)
        ray_hit = aabb.raycast(ray2)
        if ray_hit.is_hit:
            ray_hit.position = self.pose.transform_point(ray_hit.position)
            ray_hit.normal = self.pose.transform_direction(ray_hit.normal)
        return ray_hit

    def __repr__(self) -> str:
        return f"OBB(pose={self.pose}, half_extents={self.half_extents})"
Repository: Genesis-Embodied-AI/Genesis
File: genesis/utils/geom.py (Python)

Code before:
    B = z.shape[:-1]
    if out is None:
        out_ = np.empty((*B, 3, 3), dtype=z.dtype)
    else:
        assert out.shape == (*B, 3, 3)
        out_ = out

    z_norm = np.sqrt(np.sum(np.square(z.reshape((-1, 3))), -1)).reshape(B)

    out_[..., 2] = z
    for i in np.ndindex(B):
        z_norm_i = z_norm[i]
        R = out_[i]
        x, y, z = R.T

        if z_norm_i > gs.EPS:
            z /= z_norm_i
        else:
            z[:] = 0.0, 1.0, 0.0

        if up is not None:
            a = up[i]
        else:
            a = np.array([0.0, 1.0, 0.0], dtype=z.dtype)

        x[:] = np.cross(a, z)
        x_norm = np.linalg.norm(x)

        if x_norm <= gs.EPS:
            a_fallback = np.array([1.0, 0.0, 0.0], dtype=z.dtype)
            x[:] = np.cross(a_fallback, z)
            x_norm = np.linalg.norm(x)

        x /= x_norm
        y[:] = np.cross(z, x)

    return out_


def _tc_z_up_to_R(z, up=None, out=None):
    B = z.shape[:-1]
    if out is None:
        R = torch.empty((*B, 3, 3), dtype=z.dtype, device=z.device)
    else:
        assert out.shape == (*B, 3, 3)
        R = out

    # Set z as the third column of rotation matrix
    R[..., 2] = z

    # Handle batch dimension properly

Review comment (refactor):
Remove this change. You just need to update the special case:
```python
        else:
            x[0] = z[2]
            x[1] = 0.0
            x[2] = -z[0]
```

Code after:
    B = z.shape[:-1]
    if out is None:
        out_ = np.empty((*B, 3, 3), dtype=z.dtype)
    else:
        assert out.shape == (*B, 3, 3)
        out_ = out

    z_norm = np.sqrt(np.sum(np.square(z.reshape((-1, 3))), -1)).reshape(B)

    out_[..., 2] = z
    for i in np.ndindex(B):
        z_norm_i = z_norm[i]
        R = out_[i]
        x, y, z = R.T

        if z_norm_i > gs.EPS:
            z /= z_norm_i
        else:
            if up is None or abs(up[i][1]) < 0.5:
                z[:] = 0.0, 1.0, 0.0
            else:
                z[:] = 0.0, 0.0, 1.0

        if up is not None:
            x[:] = np.cross(up[i], z)
        else:
            if abs(z[2]) < 1.0 - gs.EPS:
                # up = (0.0, 0.0, 1.0)
                x[0] = z[1]
                x[1] = -z[0]
                x[2] = 0.0
            else:
                # up = (0.0, 1.0, 0.0)
                x[0] = z[2]
                x[1] = 0.0
                x[2] = -z[0]

        x_norm = np.linalg.norm(x)
        if x_norm > gs.EPS:
            x /= x_norm
            y[:] = np.cross(z, x)
        else:
            # This would only occurs if the user specified non-zero colinear z and up
            R[:] = np.eye(3, dtype=R.dtype)

    return out_


def _tc_z_up_to_R(z, up=None, out=None):
    B = z.shape[:-1]
    if out is None:
Repository: Genesis-Embodied-AI/Genesis
File: genesis/utils/geom.py (Python)

Code before:

    z_norm = np.sqrt(np.sum(np.square(z.reshape((-1, 3))), -1)).reshape(B)

    out_[..., 2] = z
    for i in np.ndindex(B):
        z_norm_i = z_norm[i]
        R = out_[i]
        x, y, z = R.T

        if z_norm_i > gs.EPS:
            z /= z_norm_i
        else:
            z[:] = 0.0, 1.0, 0.0

        if up is not None:
            a = up[i]
        else:
            a = np.array([0.0, 1.0, 0.0], dtype=z.dtype)

        x[:] = np.cross(a, z)
        x_norm = np.linalg.norm(x)

        if x_norm <= gs.EPS:
            a_fallback = np.array([1.0, 0.0, 0.0], dtype=z.dtype)
            x[:] = np.cross(a_fallback, z)
            x_norm = np.linalg.norm(x)

        x /= x_norm
        y[:] = np.cross(z, x)

    return out_


def _tc_z_up_to_R(z, up=None, out=None):
    B = z.shape[:-1]
    if out is None:
        R = torch.empty((*B, 3, 3), dtype=z.dtype, device=z.device)
    else:
        assert out.shape == (*B, 3, 3)
        R = out

    # Set z as the third column of rotation matrix
    R[..., 2] = z

    # Handle batch dimension properly
    x, y, z = R[..., 0], R[..., 1], R[..., 2]

    # Normalize z vectors
    z_norm = torch.linalg.norm(z, dim=-1, keepdim=True)
    z /= z_norm.clamp(min=gs.EPS)


Review comment (suggestion):
You should rather adapt the special case to detect whether `x_norm < gs.EPS` before setting it. Basically, you just need to check `z[1] > math.sqrt(1.0 - gs.EPS ** 2)`, then use `axis = (1.0, 0.0, 0.0)` otherwise (virtually, without actually cross product).

Code after:

    z_norm = np.sqrt(np.sum(np.square(z.reshape((-1, 3))), -1)).reshape(B)

    out_[..., 2] = z
    for i in np.ndindex(B):
        z_norm_i = z_norm[i]
        R = out_[i]
        x, y, z = R.T

        if z_norm_i > gs.EPS:
            z /= z_norm_i
        else:
            if up is None or abs(up[i][1]) < 0.5:
                z[:] = 0.0, 1.0, 0.0
            else:
                z[:] = 0.0, 0.0, 1.0

        if up is not None:
            x[:] = np.cross(up[i], z)
        else:
            if abs(z[2]) < 1.0 - gs.EPS:
                # up = (0.0, 0.0, 1.0)
                x[0] = z[1]
                x[1] = -z[0]
                x[2] = 0.0
            else:
                # up = (0.0, 1.0, 0.0)
                x[0] = z[2]
                x[1] = 0.0
                x[2] = -z[0]

        x_norm = np.linalg.norm(x)
        if x_norm > gs.EPS:
            x /= x_norm
            y[:] = np.cross(z, x)
        else:
            # This would only occurs if the user specified non-zero colinear z and up
            R[:] = np.eye(3, dtype=R.dtype)

    return out_


def _tc_z_up_to_R(z, up=None, out=None):
    B = z.shape[:-1]
    if out is None:
        R = torch.empty((*B, 3, 3), dtype=z.dtype, device=z.device)
    else:
        assert out.shape == (*B, 3, 3)
        R = out

    # Set z as the third column of rotation matrix
Repository: Genesis-Embodied-AI/Genesis
File: genesis/sensors/raycaster/depth_camera.py (Python)

Code before:
from .patterns import DepthCameraPattern
from .raycaster import RaycasterData, RaycasterOptions, RaycasterSensor, RaycasterSharedMetadata


class DepthCameraOptions(RaycasterOptions):
    """
    Depth camera that uses ray casting to obtain depth images.

    Parameters
    ----------
    pattern: DepthCameraPattern
        The raycasting pattern configuration for the sensor.
    """

    pattern: DepthCameraPattern


@register_sensor(DepthCameraOptions, RaycasterSharedMetadata, RaycasterData)
class DepthCameraSensor(RaycasterSensor):

    def build(self):
        super().build()
        self._shape = ((self._manager._sim._B,) if self._manager._sim.n_envs > 0 else ()) + (
            self._options.pattern.height,
            self._options.pattern.width,
        )

    def read_image(self) -> torch.Tensor:
        """
        Read the depth image from the sensor.

        This method uses the hit distances from the underlying RaycasterSensor.read() method and reshapes into image.

        Returns
        -------
        torch.Tensor
            The depth image with shape (height, width).
        """
        return self.read().distances.reshape(*self._shape)


Review comment (performance):
This is not readable. You should rather do:
```python
batch_shape = (self._manager._sim._B,) if self._manager._sim.n_envs > 0 else ()
self._shape = (*batch_shape, self._options.pattern.height, self._options.pattern.width)
```

Code after:
from .patterns import DepthCameraPattern
from .raycaster import RaycasterData, RaycasterOptions, RaycasterSensor, RaycasterSharedMetadata


class DepthCameraOptions(RaycasterOptions):
    """
    Depth camera that uses ray casting to obtain depth images.

    Parameters
    ----------
    pattern: DepthCameraPattern
        The raycasting pattern configuration for the sensor.
    """

    pattern: DepthCameraPattern


@register_sensor(DepthCameraOptions, RaycasterSharedMetadata, RaycasterData)
class DepthCameraSensor(RaycasterSensor):

    def build(self):
        super().build()
        batch_shape = (self._manager._sim._B,) if self._manager._sim.n_envs > 0 else ()
        self._shape = (*batch_shape, self._options.pattern.height, self._options.pattern.width)

    def read_image(self) -> torch.Tensor:
        """
        Read the depth image from the sensor.

        This method uses the hit distances from the underlying RaycasterSensor.read() method and reshapes into image.

        Returns
        -------
        torch.Tensor
            The depth image with shape (height, width).
        """
        return self.read().distances.reshape(*self._shape)