Python DepthImage
A depth image backed by shared memory for zero-copy inter-process communication. Supports F32 (meters) and U16 (millimeters) formats. Use for stereo cameras, structured light sensors (RealSense, Kinect), and ToF cameras.
When to Use
Use DepthImage when you need per-pixel depth values with typed access (get_depth() returns meters, depth_statistics() gives min/max/mean). For raw 16-bit depth transport without typed access, use Image with "depth16" encoding instead.
ROS2 equivalent: sensor_msgs/Image with encoding=32FC1 — but HORUS adds typed depth access methods and statistics.
Constructor
from horus import DepthImage
# F32 depth image (meters) — most common
depth = DepthImage(height=480, width=640, dtype="float32")
# U16 depth image (millimeters) — RealSense raw output
depth_u16 = DepthImage(height=480, width=640, dtype="uint16")
Parameters:
height: int— Image height in pixelswidth: int— Image width in pixelsdtype: str—"float32"(meters) or"uint16"(millimeters). Default:"float32"
Factory Methods
# From NumPy — shape (H, W), dtype auto-detected
import numpy as np
depth_data = np.random.uniform(0.5, 5.0, (480, 640)).astype(np.float32)
depth = DepthImage.from_numpy(depth_data)
# From PyTorch tensor
import torch
depth = DepthImage.from_torch(torch.randn(480, 640))
Properties
| Property | Type | Description |
|---|---|---|
height | int | Image height |
width | int | Image width |
dtype | str | "float32" or "uint16" |
nbytes | int | Total data size in bytes |
frame_id | str | Camera coordinate frame |
timestamp_ns | int | Timestamp in nanoseconds |
depth_scale | float | Scale factor (1.0 for meters, 0.001 for mm→m) |
Format Queries
depth.is_meters() # True if F32 (float32)
depth.is_millimeters() # True if U16 (uint16)
Methods
Depth Access
# Get depth at pixel — always returns meters as float
d = depth.get_depth(320, 240)
print(f"Center depth: {d:.3f}m")
# Set depth at pixel — value in meters
depth.set_depth(100, 100, 1.5)
# Statistics (min, max, mean) — None if all pixels are invalid/zero
stats = depth.depth_statistics()
if stats:
min_d, max_d, mean_d = stats
print(f"Range: {min_d:.2f}–{max_d:.2f}m, mean: {mean_d:.2f}m")
| Method | Signature | Description |
|---|---|---|
get_depth(x, y) | (int, int) -> float | Depth in meters at pixel |
set_depth(x, y, val) | (int, int, float) -> None | Set depth in meters |
depth_statistics() | () -> Optional[tuple[float, float, float]] | (min, max, mean) in meters |
Framework Conversions
# To NumPy — zero-copy, shape (H, W)
np_depth = depth.to_numpy()
# To PyTorch — zero-copy via DLPack
torch_depth = depth.to_torch()
# To JAX — zero-copy via DLPack
jax_depth = depth.to_jax()
Metadata
depth.set_frame_id("depth_camera")
depth.set_timestamp_ns(horus.timestamp_ns())
Complete Example
import horus
from horus import DepthImage, Topic
import numpy as np
depth_topic = Topic(DepthImage)
def depth_camera_tick(node):
# Simulate depth camera (0.3m–10m range)
raw = np.random.uniform(0.3, 10.0, (480, 640)).astype(np.float32)
depth = DepthImage.from_numpy(raw)
depth.set_frame_id("realsense_depth")
depth_topic.send(depth)
def safety_tick(node):
depth = depth_topic.recv()
if depth:
stats = depth.depth_statistics()
if stats:
min_d, _, _ = stats
if min_d < 0.5:
node.log_warning(f"Object at {min_d:.2f}m — too close!")
# Check specific region (center pixel)
center_d = depth.get_depth(320, 240)
if center_d < 1.0:
node.log_error(f"Collision risk: {center_d:.2f}m ahead")
camera = horus.Node(name="depth_cam", tick=depth_camera_tick, rate=30, order=0, pubs=["depth"])
safety = horus.Node(name="safety", tick=safety_tick, rate=30, order=1, subs=["depth"])
horus.run(camera, safety)
Design Decisions
Why separate DepthImage instead of Image with depth encoding? Image with "depth16" encoding gives you raw 16-bit values with no unit semantics. DepthImage adds typed depth access: get_depth() always returns meters (auto-converting from mm for U16), and depth_statistics() computes min/max/mean. Use Image for transport, DepthImage for processing.
Why F32 and U16 but not F64 or U32? F32 (meters) gives 7 decimal digits of precision — sub-millimeter accuracy up to 1 km. More than any depth sensor provides. U16 (millimeters) covers 0–65.5m range, matching RealSense/Kinect native output. F64 and U32 would double memory usage with no practical benefit.
See Also
- Image (Python) — Camera images
- PointCloud (Python) — 3D point clouds
- Image (Stdlib) — Image message type overview