Point Cloud Colouring Pipeline
Colours 3D point clouds by projecting each point onto the calibrated RGB and IR
cameras and sampling pixel colours. Each output PLY carries dual texture:
RGB colours (from rg_*.bmp) and IR colours (from ir_*.png), stored as separate
per-vertex properties so both can be visualised in CloudCompare or any PLY viewer.
Core module: colour_ply.py
| Function | Purpose |
|---|---|
load_ascii_ply(ply_path) |
Read ASCII PLY, return Nx3 float32 xyz array |
colorize_combined_pointcloud(pts, rgb_img, ir_img, lc_rgb_yaml, lc_ir_yaml, lc_rc_yaml, out_ply) |
Un-rotate points using R1 from stereo rectification, project to RGB + IR cameras, save dual-texture binary PLY |
save_master_ply(filename, points, rgb_colors, ir_colors) |
Write binary_little_endian PLY with x,y,z,red,green,blue,ir_red,ir_green,ir_blue |
Folder structure assumed
~/Speckle-Scanner_Processing_data/
└── <project>/
└── <date>/
└── <session>/
├── params_link/
│ ├── lc-rc_stereo_cam_model.yaml ← stereoRectify R1 (un-rotate 3D points)
│ ├── lc-rg_stereo_cam_model.yaml ← project to RGB camera
│ └── lc-ir_stereo_cam_model.yaml ← project to IR camera
└── <ScanXXXXXX>/
├── 02_rect_images/
│ ├── ir_*.png ← one IR image (input)
│ └── rg_*.bmp ← one RGB image (input)
├── 05_sgm_pcl/
│ └── Point_cloud.ply ← SGM point cloud (input)
├── 06_zncc_pcl/
│ └── Point_cloud.ply ← ZNCC point cloud (input)
├── 07_sgm_pcl_col/
│ └── Point_cloud_colored.ply ← SGM coloured output (created)
└── 08_zncc_pcl_col/
└── Point_cloud_colored.ply ← ZNCC coloured output (created)
Pipeline commands
cd ~/Speckle-Scanner/09_coloring
# Both SGM + ZNCC — all scans in a session
python run_coloring_pipeline.py \
--project Olsen_wings \
--date 2026-05-12 \
--session session1
# Both SGM + ZNCC — all sessions on a date (omit --session)
python run_coloring_pipeline.py \
--project Olsen_wings \
--date 2026-05-12
# Single scan, both modes
python run_coloring_pipeline.py \
--project Olsen_wings \
--date 2026-05-12 \
--session session1 \
--scan Scan000001
# Single scan, SGM only
python run_coloring_pipeline.py \
--project Olsen_wings \
--date 2026-05-12 \
--session session1 \
--scan Scan000001 \
--mode sgm
# Single scan, ZNCC only
python run_coloring_pipeline.py \
--project Olsen_wings \
--date 2026-05-12 \
--session session1 \
--scan Scan000001 \
--mode zncc
Parameters
| Parameter | Default | Description |
|---|---|---|
--project |
— | Project name (e.g. Olsen_wings) |
--date |
— | Date string (e.g. 2026-05-12) |
--session |
all | Session name (e.g. session1); omit to process all sessions on that date |
--scan |
all | Single scan (e.g. Scan000001); omit to process all scans in the session |
--mode |
both |
Which point cloud to colour: sgm, zncc, or both |
What gets saved
| File | Description |
|---|---|
07_sgm_pcl_col/Point_cloud_colored.ply |
SGM cloud with RGB + IR dual texture (binary PLY) |
08_zncc_pcl_col/Point_cloud_colored.ply |
ZNCC cloud with RGB + IR dual texture (binary PLY) |
The output PLY has the following vertex properties:
x, y, z — 32-bit float (metres)
red, green, blue — 8-bit uchar (from rg_*.bmp camera)
ir_red, ir_green, ir_blue — 8-bit uchar (from ir_*.png camera)
To visualise the IR texture in CloudCompare, select the ir_red/ir_green/ir_blue
scalar fields or load the file and choose the IR colour attribute.
Skip conditions
The runner prints [SKIP] and moves to the next scan if any required file is absent:
02_rect_images/ir_*.png— no IR image found02_rect_images/rg_*.bmp— no RGB image foundparams_link/lc-rc_stereo_cam_model.yaml— missing RC YAMLparams_link/lc-rg_stereo_cam_model.yaml— missing RG YAMLparams_link/lc-ir_stereo_cam_model.yaml— missing IR YAML05_sgm_pcl/Point_cloud.ply— SGM cloud not generated yet (runrun_pcl_pipeline.py --mode sgmfirst)06_zncc_pcl/Point_cloud.ply— ZNCC cloud not generated yet (runrun_pcl_pipeline.py --mode znccfirst)
Dependencies
# This step only
pip install -r ~/Speckle-Scanner/09_coloring/requirements.txt
# Or install everything for the full pipeline
pip install -r ~/Speckle-Scanner/requirements.txt
Packages: numpy, opencv-python.