Compare commits
2 Commits
14ae0a901f
...
2016b14f91
| Author | SHA1 | Date | |
|---|---|---|---|
| 2016b14f91 | |||
| 1740f9d6fc |
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build*/
|
||||||
|
datasets/
|
||||||
|
*.ply
|
||||||
|
*.tar.gz
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,3 +20,4 @@ large_tool_results/
|
|||||||
|
|
||||||
# Point-cloud exports
|
# Point-cloud exports
|
||||||
*.ply
|
*.ply
|
||||||
|
build-docker/
|
||||||
|
|||||||
49
Dockerfile
49
Dockerfile
@ -1,38 +1,39 @@
|
|||||||
# Use Ubuntu 24.04 as base (matching development environment)
|
# Build-environment image: contains the toolchain and dependencies only.
|
||||||
|
# The source tree is bind-mounted at runtime and compiled inside the container:
|
||||||
|
#
|
||||||
|
# docker build -t cloud-point-rpc-dev .
|
||||||
|
# docker run -d --name cprpc-dev --network=host -v "$(pwd)":/app cloud-point-rpc-dev
|
||||||
|
# docker exec -it cprpc-dev meson setup build-docker
|
||||||
|
# docker exec -it cprpc-dev meson compile -C build-docker
|
||||||
|
# docker exec -it cprpc-dev ./build-docker/src/cloud_point_rpc_cli config.yml
|
||||||
|
#
|
||||||
|
# Use a dedicated build directory (build-docker) so host and container
|
||||||
|
# builds never share Meson state.
|
||||||
FROM ubuntu:24.04
|
FROM ubuntu:24.04
|
||||||
|
|
||||||
# Avoid interactive prompts during package installation
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
# Install dependencies
|
# - build-essential, meson, ninja-build, cmake, pkg-config: toolchain
|
||||||
# - build-essential: Compiler (gcc/g++)
|
# - git: Meson subprojects (asio, json, yaml-cpp, glog, jsonrpccxx, gtest)
|
||||||
# - meson/ninja-build: Build system
|
# - libopencv-dev: OpenCV 4 incl. contrib modules (ximgproc for the WLS filter)
|
||||||
# - git: For fetching subprojects
|
# - libunwind-dev: glog stack traces
|
||||||
# - pkg-config, cmake: For dependency resolution
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
# - libssl-dev: Often needed for cmake fetches/networking
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
build-essential \
|
build-essential \
|
||||||
meson \
|
meson \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
git \
|
|
||||||
pkg-config \
|
|
||||||
cmake \
|
cmake \
|
||||||
|
pkg-config \
|
||||||
|
git \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
libunwind-dev \
|
libunwind-dev \
|
||||||
|
libopencv-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Set working directory
|
# The mounted checkout is usually owned by a different uid than root inside
|
||||||
|
# the container; git refuses to touch it otherwise (Meson subprojects need git).
|
||||||
|
RUN git config --global --add safe.directory '*'
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy project files
|
# Keep the container alive; build and run via `docker exec`.
|
||||||
COPY . .
|
CMD ["tail", "-F", "/dev/null"]
|
||||||
|
|
||||||
# Setup build directory and compile
|
|
||||||
# We allow git to fetch subprojects (glog, gtest, asio, etc.)
|
|
||||||
RUN meson setup build && \
|
|
||||||
meson compile -C build
|
|
||||||
|
|
||||||
# Run the cli by default
|
|
||||||
# We assume the config.yaml is in the root /app or we copy it.
|
|
||||||
# The build output is in build/src/cloud_point_rpc_cli
|
|
||||||
CMD ["./build/src/cloud_point_rpc_cli", "config.yaml"]
|
|
||||||
|
|||||||
98
README.md
98
README.md
@ -12,9 +12,24 @@ Communication JSON RPC protocol and implementation with Unity Scene.
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
|
Done:
|
||||||
|
|
||||||
- [x] Server implementation with C-API for Unity
|
- [x] Server implementation with C-API for Unity
|
||||||
- [x] OpenCV stereo client (StereoRectifier, PointCloudBuilder, CloudPointClient facade)
|
- [x] OpenCV stereo client (StereoRectifier, CPU/GPU matchers, PointCloudBuilder, CloudPointClient facade)
|
||||||
- [ ] Unity-side C# implementation per [docs/unity-integration.md](docs/unity-integration.md)
|
- [x] Tuned SGBM for the SCARED rig (P1/P2 penalties, uniqueness, speckle, LRC) and depth-range clipping
|
||||||
|
- [x] Binary PLY export with grid triangulation and `ply_stride` decimation
|
||||||
|
- [x] Optional WLS / median disparity post-filters (`wls_filter`, `CpuStereoMatcher::Params`)
|
||||||
|
- [x] SCARED benchmark with ground-truth metrics, depth PNGs and `scripts/scared_overview.py`
|
||||||
|
- [x] Unity-side C# implementation per [docs/unity-integration.md](docs/unity-integration.md)
|
||||||
|
|
||||||
|
To do:
|
||||||
|
- [ ] Remove sliver triangles at the border of the valid region (long spikes are still visible in
|
||||||
|
shaded viewers at `ply_stride: 4` because 5 % of local depth allows 3 mm edges)
|
||||||
|
- [ ] Visually compare raw vs WLS meshes in a shaded web viewer and decide the visualisation default
|
||||||
|
- [ ] Expose the remaining `CpuStereoMatcher::Params` (block size, uniqueness, speckle, median kernel,
|
||||||
|
WLS lambda/sigma) in the YAML `cloud_point` section
|
||||||
|
- [ ] Validate the CUDA `StereoSGM` path on a GPU machine (currently only exercised via CPU fallback)
|
||||||
|
- [ ] Reduce sub-pixel SGBM noise without the WLS accuracy loss (e.g. bilateral or guided filter on depth)
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
@ -22,7 +37,17 @@ See [API.md](API.md) for detailed request/response formats.
|
|||||||
|
|
||||||
## Pipeline
|
## Pipeline
|
||||||
|
|
||||||
Unity acts as a data source: it serves stereo image pairs (`get-image-pair`) and full stereo calibration (`get-stereo-calibration`) over JSON-RPC 2.0. The C++ `CloudPointClient` calls `connect()` once to fetch calibration, then on each `compute_cloud()` call it fetches a synchronised image pair, runs stereo rectification (`StereoRectifier`, cv::stereoRectify + remap), computes disparity with SGBM (16× scaling), reprojects to 3-D with `cv::reprojectImageTo3D` (`PointCloudBuilder`), filters NaN/invalid points, and returns a `PointCloud`. An optional `write_ply()` helper serialises the result to disk.
|
Unity acts as a data source: it serves stereo image pairs (`get-image-pair`) and full stereo calibration (`get-stereo-calibration`) over JSON-RPC 2.0. The C++ `CloudPointClient` calls `connect()` once to fetch calibration, then on each `compute_cloud()` call it fetches a synchronised image pair and runs the stages below.
|
||||||
|
|
||||||
|
| Stage | Class | Algorithm |
|
||||||
|
|-------|-------|-----------|
|
||||||
|
| Rectification | `StereoRectifier` | `cv::stereoRectify` + `initUndistortRectifyMap`/`remap`; also yields the Q reprojection matrix |
|
||||||
|
| Disparity (CPU) | `CpuStereoMatcher` | `cv::StereoSGBM` (semi-global block matching, `MODE_SGBM`, 16× fixed point) with optional median blur or `cv::ximgproc` WLS post-filter |
|
||||||
|
| Disparity (GPU) | `GpuStereoMatcher` | `cv::cuda::StereoSGM` (`MODE_HH4`, 64/128/256 disparity levels); default, falls back to CPU without CUDA |
|
||||||
|
| Reprojection | `PointCloudBuilder` | `cv::reprojectImageTo3D` with Q, then rejects disparity ≤ 0, OpenCV sentinels and depth outside `[min_depth_m, max_depth_m]` |
|
||||||
|
| Export | `write_ply` | Binary little-endian PLY with grid triangulation (edges ≤ 5 % of local depth) and optional `stride` block averaging |
|
||||||
|
|
||||||
|
`StereoMatcherFactory` picks the matcher from `CloudPointConfig::algorithm` and forwards `CpuStereoMatcher::Params`. Depth follows `z = fx·B / disparity`; on the SCARED rig that is about `4.45 m / disparity_px`, which is why the disparity range and depth limits in `config.scared.yml` matter.
|
||||||
|
|
||||||
See [API.md](API.md) for wire schemas and [docs/unity-integration.md](docs/unity-integration.md) for the Unity C# design spec.
|
See [API.md](API.md) for wire schemas and [docs/unity-integration.md](docs/unity-integration.md) for the Unity C# design spec.
|
||||||
|
|
||||||
@ -101,27 +126,43 @@ meson test -C build -v
|
|||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
You can build and run the cli using `Docker`.
|
The `Dockerfile` builds a **development environment** image only: toolchain
|
||||||
|
(GCC, Meson, Ninja, CMake), git for the Meson subprojects and OpenCV 4 with
|
||||||
|
contrib modules. Nothing is compiled at image build time. The source tree is
|
||||||
|
bind-mounted into the running container and compiled there, so edits on the
|
||||||
|
host are picked up immediately and the build artefacts land in your checkout.
|
||||||
|
|
||||||
### 1. Build Image
|
### 1. Build the environment image
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t cloud-point-rpc .
|
docker build -t cloud-point-rpc-dev .
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Run Container
|
### 2. Start the container with the source mounted
|
||||||
|
|
||||||
The cli will try to connect to a **running server** on ip and port defined in config.yml file. (defined in `config.yaml` inside the image).
|
|
||||||
For simplicity, it's better to use a host network, so you will not have any headache with accessability.
|
|
||||||
|
|
||||||
> _Server is not configured to run through container, if you need, contact me_
|
|
||||||
|
|
||||||
You also can mount your own `config.yaml` to override the default settings:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --network=host -it -v $(pwd)/my_config.yaml:/app/config.yaml cloud-point-rpc
|
docker run -d --name cprpc-dev --network=host -v "$(pwd)":/app cloud-point-rpc-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The container idles (`tail -F /dev/null`); `--network=host` lets the CLI
|
||||||
|
reach a server running on the host and lets the server be reached from Unity.
|
||||||
|
|
||||||
|
### 3. Build and run inside the container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it cprpc-dev meson setup build-docker
|
||||||
|
docker exec -it cprpc-dev meson compile -C build-docker
|
||||||
|
docker exec -it cprpc-dev meson test -C build-docker
|
||||||
|
docker exec -it cprpc-dev ./build-docker/src/cloud_point_rpc_cli config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Use a dedicated build directory such as `build-docker`: Meson stores absolute
|
||||||
|
compiler paths, so a build directory configured on the host cannot be reused
|
||||||
|
inside the container and vice versa. With rootless Docker the container's
|
||||||
|
root maps to your host user, so `build-docker/` stays owned by you; with a
|
||||||
|
rootful daemon add `--user "$(id -u):$(id -g)"` to `docker run` to avoid
|
||||||
|
root-owned build files.
|
||||||
|
|
||||||
## Validation with SCARED Dataset
|
## Validation with SCARED Dataset
|
||||||
|
|
||||||
The `scared_dataset_server` executable lets you validate the stereo point-cloud
|
The `scared_dataset_server` executable lets you validate the stereo point-cloud
|
||||||
@ -241,12 +282,27 @@ prints a Markdown table:
|
|||||||
```bash
|
```bash
|
||||||
scripts/scared_overview.py --png-dir out/depth --depth-range 0.02 0.30 \
|
scripts/scared_overview.py --png-dir out/depth --depth-range 0.02 0.30 \
|
||||||
datasets/scared/dataset_1/keyframe_* datasets/scared/test_dataset_8/keyframe_*
|
datasets/scared/dataset_1/keyframe_* datasets/scared/test_dataset_8/keyframe_*
|
||||||
``` OBJ coordinates are
|
```
|
||||||
converted from millimetres to metres and rectified into the same left-camera
|
|
||||||
frame as the reconstructed cloud before evaluation. Reference numbers for
|
Ground-truth OBJ coordinates are converted from millimetres to metres and
|
||||||
`dataset_1/keyframe_1` with the tuned SGBM configuration: coverage ≈ 0.85,
|
rectified into the same left-camera frame as the reconstructed cloud before
|
||||||
MAE₃D ≈ 0.8 mm, RMSE₃D ≈ 1.4 mm, 80 % of points within 2 mm (the previous
|
evaluation. Reference numbers with the tuned SGBM configuration and the
|
||||||
unregularised SGBM gave MAE₃D ≈ 44 mm and RMSE₃D ≈ 289 mm).
|
0.02–0.30 m depth range (raw disparity, no WLS):
|
||||||
|
|
||||||
|
| Keyframe | Valid points | MAE₃D | RMSE₃D | Within 2 mm |
|
||||||
|
|----------|--------------|-------|--------|-------------|
|
||||||
|
| dataset_1 kf1 | 84.6 % | 0.84 mm | 1.43 mm | 80 % |
|
||||||
|
| dataset_1 kf2 | 86.3 % | 1.15 mm | 2.05 mm | 76 % |
|
||||||
|
| dataset_1 kf3 | 86.9 % | 1.09 mm | 8.15 mm | 76 % |
|
||||||
|
| dataset_1 kf4 | 84.7 % | 0.66 mm | 1.26 mm | 85 % |
|
||||||
|
| dataset_1 kf5 | 84.6 % | 0.79 mm | 1.51 mm | 77 % |
|
||||||
|
| dataset_2 kf1 | 72 % | 1.10 mm | 3.76 mm | — (near tissue at the disparity limit) |
|
||||||
|
| dataset_3 kf1 | 83.6 % | 1.75 mm | 4.06 mm | 67 % |
|
||||||
|
| test_dataset_8 kf0–4 | 79–86 % | no ground truth; median depth 56–115 mm | | |
|
||||||
|
|
||||||
|
The previous unregularised SGBM gave MAE₃D ≈ 44 mm and RMSE₃D ≈ 289 mm on
|
||||||
|
`dataset_1/keyframe_1`. Matching takes ~325 ms per 1280×1024 frame on the
|
||||||
|
CPU (~650 ms with WLS).
|
||||||
|
|
||||||
The E2E test (`tests/test_scared_dataset.cpp`) exercises the same pipeline
|
The E2E test (`tests/test_scared_dataset.cpp`) exercises the same pipeline
|
||||||
with `num_disparities = 160` and asserts >50 000 valid points and a median
|
with `num_disparities = 160` and asserts >50 000 valid points and a median
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user