feat(bringup): D435i depth hole filler via bilateral interpolation (Issue #268) #271

Merged
sl-jetson merged 1 commits from sl-perception/issue-268-depth-holes into main 2026-03-02 17:26:25 -05:00
Collaborator

Summary

  • Pure-Python _depth_hole_fill.py: valid_mask() (zero/NaN/out-of-range → False); fill_holes(depth, kernel_size=5, d_min=0.1, d_max=10.0, max_passes=3) — fully-vectorised multi-pass spatial-Gaussian hole fill using cv2.filter2D; formula: filled = Σ G(dist)·d_valid / Σ G(dist) over valid neighbours; passes use kernels scaled ×1/×2.5/×6 so small→large holes are covered; original valid pixels are never modified; BORDER_REFLECT prevents artefacts at image edges
  • depth_hole_fill_node.py: subscribes /camera/depth/image_rect_raw (BEST_EFFORT, configurable); handles uint16 mm→float32 m auto-conversion; publishes filled float32 on /camera/depth/filled at camera rate; output suitable for VO, RTAB-Map, floor classifier

Test plan

  • test/test_depth_hole_fill.py — 37/37 pure-Python tests pass (no ROS2 required)
  • Covers: valid_mask, kernel size, output contract, single-pixel zero/NaN fill, row of holes, all-zero image, border holes, gradient interpolation, 9×9 hole vs pass count, depth range guard
  • Deploy on Jetson: compare /camera/depth/image_rect_raw vs /camera/depth/filled in RViz — confirm black regions (holes) are filled
  • Verify latency < 5 ms per frame at 640×480

🤖 Generated with Claude Code

## Summary - Pure-Python `_depth_hole_fill.py`: `valid_mask()` (zero/NaN/out-of-range → False); `fill_holes(depth, kernel_size=5, d_min=0.1, d_max=10.0, max_passes=3)` — fully-vectorised multi-pass spatial-Gaussian hole fill using `cv2.filter2D`; formula: `filled = Σ G(dist)·d_valid / Σ G(dist)` over valid neighbours; passes use kernels scaled ×1/×2.5/×6 so small→large holes are covered; original valid pixels are never modified; `BORDER_REFLECT` prevents artefacts at image edges - `depth_hole_fill_node.py`: subscribes `/camera/depth/image_rect_raw` (BEST_EFFORT, configurable); handles uint16 mm→float32 m auto-conversion; publishes filled float32 on `/camera/depth/filled` at camera rate; output suitable for VO, RTAB-Map, floor classifier ## Test plan - [x] `test/test_depth_hole_fill.py` — 37/37 pure-Python tests pass (no ROS2 required) - Covers: valid_mask, kernel size, output contract, single-pixel zero/NaN fill, row of holes, all-zero image, border holes, gradient interpolation, 9×9 hole vs pass count, depth range guard - [ ] Deploy on Jetson: compare `/camera/depth/image_rect_raw` vs `/camera/depth/filled` in RViz — confirm black regions (holes) are filled - [ ] Verify latency < 5 ms per frame at 640×480 🤖 Generated with [Claude Code](https://claude.com/claude-code)
sl-perception added 1 commit 2026-03-02 14:19:54 -05:00
Adds multi-pass spatial-Gaussian hole filler for D435i depth images.
Each pass replaces zero/NaN pixels with the Gaussian-weighted mean of valid
neighbours in a growing kernel (×1, ×2.5, ×6 default); original valid
pixels are never modified.  Handles uint16 mm → float32 m conversion,
border pixels via BORDER_REFLECT, and above-d_max pixels as holes.
Publishes filled float32 depth on /camera/depth/filled at camera rate.
37/37 pure-Python tests pass (no ROS2 required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sl-jetson merged commit 01ee02f837 into main 2026-03-02 17:26:25 -05:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: seb/saltylab-firmware#271
No description provided.