ReUseX  0.0.5
3D Point Cloud Processing for Building Reuse
Loading...
Searching...
No Matches
reusex::io Namespace Reference

Namespaces

namespace  speckle

Classes

struct  ArkitPincam
 Parsed contents of an ARKitScenes .pincam intrinsics line. More...
struct  ArkitPoseSample
 One trajectory sample: a device-relative timestamp and the optical-to-world (camera->world) pose at that instant, row-major 4x4. More...
struct  ColmapExportOptions
 Options for COLMAP sparse model export. More...
struct  E57ScanExport
 A single scan position to write into an E57 file. More...
struct  ExportScene
 Intermediate representation for exporting all project data. More...

Typedefs

using ArkitTrajectory = std::vector<ArkitPoseSample>
 Trajectory as a timestamp-ascending sequence of camera->world samples.

Functions

ArkitPincam parse_pincam (const std::string &line)
 Parse a single ARKitScenes .pincam line: width height fx fy cx cy (six whitespace-separated doubles).
std::array< double, 16 > arkit_traj_to_optical_world (double rx, double ry, double rz, double tx, double ty, double tz)
 Convert one ARKitScenes trajectory pose to an optical-to-world 4x4 matrix (row-major, 16 doubles).
ArkitTrajectory load_arkit_trajectory (const std::filesystem::path &traj_path)
 Parse the trajectory file into timestamp-sorted camera->world poses.
std::optional< std::array< double, 16 > > interpolate_pose (const ArkitTrajectory &traj, double ts, double max_gap=kArkitMaxPoseGap)
 Interpolate the camera->world pose at ts from the bracketing trajectory samples: SLERP on the rotation, linear interpolation on the camera position.
bool parse_frame_timestamp (const std::filesystem::path &file, double &ts)
 Extract the timestamp encoded in an ARKitScenes stream filename such as 41069021_452.395.png: drop the extension, then take everything after the last underscore (a bare std::stod would stop at the video-id prefix).
std::size_t import_arkitscenes (ProjectDB &db, const std::filesystem::path &scene_dir)
 Import an ARKitScenes scene (lowres iPad-LiDAR streams) into a ReUseX project.
void export_colmap_scene (const ProjectDB &db, const std::filesystem::path &out_dir, const ColmapExportOptions &opt={})
 Export a COLMAP sparse model directory from a ProjectDB.
void import_e57 (ProjectDB &db, const std::filesystem::path &e57_path)
 Import point cloud data from an E57 file into a ProjectDB.
void export_e57 (const std::filesystem::path &path, const std::vector< E57ScanExport > &scans)
 Export one or more XYZRGB clouds as separate scan positions in an E57 file.
double read_exif_timestamp (const std::filesystem::path &jpeg_path)
 Read EXIF DateTimeOriginal from a JPEG file.
ExportScene gather_export_scene (const ProjectDB &db)
 Gather all exportable data from a ProjectDB.
std::size_t import_mushroom (ProjectDB &db, const std::filesystem::path &capture_dir)
 Import a MuSHRoom dataset capture directory into a ReUseX project.
void import_ply (ProjectDB &db, const std::filesystem::path &ply_path)
 Import a point cloud from a PLY file into a ProjectDB.
void export_ply (const std::filesystem::path &path, const Cloud &cloud, const CloudN *normals=nullptr)
 Export a point cloud to a binary PLY file.
auto getPlanes (CloudLConstPtr planes, CloudNConstPtr normals, CloudLocConstPtr locations) -> std::tuple< EigenVectorContainer< double, 4 >, EigenVectorContainer< double, 3 >, std::vector< IndicesPtr > >
 Extract plane data from labeled point clouds.
bool save (std::filesystem::path const &output_path, std::vector< pcl::ModelCoefficients > const &model_coefficients, std::vector< Eigen::Vector4f, Eigen::aligned_allocator< Eigen::Vector4f > > const &centroids, std::vector< std::shared_ptr< pcl::Indices > > const &inlier_indices)
 Save plane data to file.
bool read (std::filesystem::path const &input_path, std::vector< pcl::ModelCoefficients > &model_coefficients, std::vector< Eigen::Vector4f, Eigen::aligned_allocator< Eigen::Vector4f > > &centroids, std::vector< std::shared_ptr< pcl::Indices > > &inlier_indices)
 Read plane data from file.
auto configure_rhino_model () -> std::unique_ptr< ONX_Model >
 Create a configured ONX_Model with ReUseX metadata, units, and tolerances.
auto export_to_rhino (const ExportScene &scene) -> std::unique_ptr< ONX_Model >
 Export a full ExportScene to a Rhino ONX_Model with layer hierarchy.
auto make_rhino_pointcloud (CloudConstPtr cloud) -> std::unique_ptr< ON_PointCloud >
 Convert a PCL XYZRGB point cloud to an ON_PointCloud.
auto make_rhino_pointcloud (CloudConstPtr cloud, CloudNConstPtr normals) -> std::unique_ptr< ON_PointCloud >
 Convert a PCL XYZRGB point cloud with normals to an ON_PointCloud.
auto make_rhino_mesh (const pcl::PolygonMesh &mesh) -> std::unique_ptr< ON_Mesh >
 Convert a PCL PolygonMesh to an ON_Mesh.
auto make_sphere_mesh (double cx, double cy, double cz, double radius, int resolution=16) -> std::unique_ptr< ON_Mesh >
 Create a UV sphere mesh.
void import_rtabmap (ProjectDB &db, const std::filesystem::path &rtabmap_db_path)
 Import raw sensor data from an RTABMap database into a ProjectDB.

Variables

constexpr double kArkitMaxPoseGap = 0.5
 Largest bracketing interval interpolate_pose will interpolate across.

Typedef Documentation

◆ ArkitTrajectory

Trajectory as a timestamp-ascending sequence of camera->world samples.

(load_arkit_trajectory guarantees the ordering; interpolate_pose requires it.)

Definition at line 55 of file arkitscenes.hpp.

Function Documentation

◆ arkit_traj_to_optical_world()

std::array< double, 16 > reusex::io::arkit_traj_to_optical_world ( double rx,
double ry,
double rz,
double tx,
double ty,
double tz )

Convert one ARKitScenes trajectory pose to an optical-to-world 4x4 matrix (row-major, 16 doubles).

(rx,ry,rz) is a Rodrigues rotation vector, (tx,ty,tz) a translation. Per Apple's traj_string_to_matrix, the assembled extrinsic E=[R|t] is world->camera, so camera->world = E.inverse(). ARKitScenes' camera frame is already the OpenCV optical convention (x-right, y-down, z-forward) — the same frame reconstruct back-projects into — so c2w is returned directly as the optical-to-world pose, with no axis flip (an inserted flip empirically fans the reconstructed walls into a spiral).

◆ configure_rhino_model()

auto reusex::io::configure_rhino_model ( ) -> std::unique_ptr< ONX_Model >

Create a configured ONX_Model with ReUseX metadata, units, and tolerances.

◆ export_colmap_scene()

void reusex::io::export_colmap_scene ( const ProjectDB & db,
const std::filesystem::path & out_dir,
const ColmapExportOptions & opt = {} )

Export a COLMAP sparse model directory from a ProjectDB.

Produces this layout under out_dir :

<out_dir>/ images/<frame_id>.jpg # one per sensor_frame sparse/0/cameras.txt # PINHOLE camera per unique intrinsics sparse/0/images.txt # one entry per sensor_frame (T_cw) sparse/0/points3D.txt # optionally seeded from LiDAR cloud

Notes

  • COLMAP requires camera-frame poses (T_cw, world -> camera). ProjectDB stores pose = T_wb (sensor base in world) and intrinsics local_transform = T_bc (camera optical in sensor base). This function composes T_wc = pose * local_transform and inverts to produce T_cw = (T_wc)^{-1}, then writes (qw, qx, qy, qz, tx, ty, tz) as COLMAP expects.
  • Intrinsics are stored as JSON in ProjectDB with no distortion model, so the PINHOLE camera model (fx, fy, cx, cy) is used directly. Images do not need to be undistorted by colmap image_undistorter — but the dense workspace step still requires running it once to set up the layout.
  • Sensor frames missing color/depth are silently skipped (mirroring reconstruct_point_clouds).
Parameters
dbSource project database (read-only access).
out_dirOutput directory; created if missing. Existing files are overwritten.
optExport options.
Exceptions
std::runtime_erroron I/O failure or if db has no sensor frames.

◆ export_e57()

void reusex::io::export_e57 ( const std::filesystem::path & path,
const std::vector< E57ScanExport > & scans )

Export one or more XYZRGB clouds as separate scan positions in an E57 file.

Each entry in scans becomes one Data3D block. RGB color is always written. Normals are written using the E57_EXT_surface_normals extension when provided.

Parameters
pathOutput .e57 file path (created or overwritten).
scansOne or more scans to embed in the file.

◆ export_ply()

void reusex::io::export_ply ( const std::filesystem::path & path,
const Cloud & cloud,
const CloudN * normals = nullptr )

Export a point cloud to a binary PLY file.

When normals is provided it must have the same number of points as cloud; both are written as a single PLY element with merged fields (x, y, z, rgb, normal_x, normal_y, normal_z).

Parameters
pathOutput .ply file path (created or overwritten).
cloudXYZRGB point cloud to export.
normalsSurface normals to merge into the output (nullptr = skip).

◆ export_to_rhino()

auto reusex::io::export_to_rhino ( const ExportScene & scene) -> std::unique_ptr< ONX_Model >

Export a full ExportScene to a Rhino ONX_Model with layer hierarchy.

◆ gather_export_scene()

ExportScene reusex::io::gather_export_scene ( const ProjectDB & db)

Gather all exportable data from a ProjectDB.

Only populates layers that have data.

◆ getPlanes()

auto reusex::io::getPlanes ( CloudLConstPtr planes,
CloudNConstPtr normals,
CloudLocConstPtr locations ) -> std::tuple< EigenVectorContainer< double, 4 >, EigenVectorContainer< double, 3 >, std::vector< IndicesPtr > >

Extract plane data from labeled point clouds.

Parameters
planesLabeled point cloud where labels indicate plane IDs.
normalsPoint cloud containing plane normals.
locationsPoint cloud containing plane centroid locations.
Returns
Tuple of (plane coefficients, centroids, inlier indices).

◆ import_arkitscenes()

std::size_t reusex::io::import_arkitscenes ( ProjectDB & db,
const std::filesystem::path & scene_dir )

Import an ARKitScenes scene (lowres iPad-LiDAR streams) into a ReUseX project.

ARKitScenes (Apple/Dehghan et al., NeurIPS 2021, research-only license) provides room-scale RGB-D sequences captured with the same iPad-LiDAR sensor class as ReUseX's own scans — an external benchmark for reconstruction quality (issue #224).

Expects the scene frames directory (the one directly containing lowres_wide.traj); if scene_dir does not contain it, one level of nesting is searched (e.g. <video_id>/ or <video_id>_frames/). The frames dir holds the per-stream folders: lowres_wide/ (RGB PNG), lowres_depth/ (CV_16UC1 mm PNG), confidence/ (CV_8UC1 {0,1,2}) and lowres_wide_intrinsics/ (<ts>.pincam), plus lowres_wide.traj.

Poses in lowres_wide.traj are world->camera in ARKit axes and are converted to optical-to-world before storage (see arkit_traj_to_optical_world). The trajectory is ~10 Hz while depth is ~60 Hz, so one frame in six lands on a trajectory sample: each frame's pose is interpolated to its own timestamp (see interpolate_pose), and frames outside the trajectory's time span are skipped. Depth is already CV_16UC1 millimeters and is passed through unchanged.

Note
Timestamps (in the stream filenames, the .traj, and the ones stored on each sensor frame) are ARKit device-relative seconds — uptime since boot, not a Unix epoch — so they are only comparable within one scene.
Parameters
dbOpen project database (frames are written to it).
scene_dirScene directory (frames dir or its parent).
Returns
Number of sensor frames imported.
Exceptions
std::runtime_erroron missing/malformed inputs or zero frames.

◆ import_e57()

void reusex::io::import_e57 ( ProjectDB & db,
const std::filesystem::path & e57_path )

Import point cloud data from an E57 file into a ProjectDB.

Each scan in the E57 file is stored as a separate named XYZRGB point cloud. Color, normals, and intensity data are extracted when available. If color is absent but intensity is present, intensity is mapped to grayscale RGB. Normals are stored as a separate cloud with a "_normals" suffix.

Cloud naming: uses the scan name from the E57 header when set, otherwise "{file_stem}_scan_{N}".

Parameters
dbTarget project database (must be open in write mode).
e57_pathPath to the source .e57 file.

◆ import_mushroom()

std::size_t reusex::io::import_mushroom ( ProjectDB & db,
const std::filesystem::path & capture_dir )

Import a MuSHRoom dataset capture directory into a ReUseX project.

MuSHRoom (Ren et al., WACV 2024, CC-BY-4.0) provides room-scale RGB-D sequences from consumer devices (iPhone LiDAR / Azure Kinect) together with Faro laser-scanned ground-truth meshes — the same sensor class as ReUseX's own iPad scans, which makes it the primary external benchmark for reconstruction quality (issue #221 / #224).

Expects a capture directory (e.g. <room>/iphone/long_capture, or its sdf_dataset_*_interp_4 subdirectory) containing the sdfstudio-style export: meta_data.json + NNNNNN_rgb.png + NNNNNN_sensor_depth.npy.

meta_data.json stores OpenCV-convention camera-to-world poses in normalized unit-box coordinates plus a worldtogt similarity transform back to the metric ground-truth-mesh frame. The importer applies that transform (keeping rotations orthonormal), so imported poses and reconstructed clouds live directly in the GT mesh frame — ready for accuracy comparison against gt_mesh.ply. Depth is stored as normalized float32 .npy and converted to metric CV_16UC1 millimeters.

Parameters
dbOpen project database (frames are written to it).
capture_dirPath to the capture directory described above.
Returns
Number of sensor frames imported.
Exceptions
std::runtime_erroron missing/malformed files.

◆ import_ply()

void reusex::io::import_ply ( ProjectDB & db,
const std::filesystem::path & ply_path )

Import a point cloud from a PLY file into a ProjectDB.

Detects available fields and extracts all data present:

  • XYZ position (required)
  • RGB color → stored as XYZRGB cloud named after the file stem
  • Normals (normal_x/y/z or nx/ny/nz) → stored as a separate cloud with a "_normals" suffix
  • Semantic labels → stored as a separate cloud with a "_labels" suffix
  • Intensity without color → mapped to grayscale RGB
Parameters
dbTarget project database (must be open in write mode).
ply_pathPath to the source .ply file.

◆ import_rtabmap()

void reusex::io::import_rtabmap ( ProjectDB & db,
const std::filesystem::path & rtabmap_db_path )

Import raw sensor data from an RTABMap database into a ProjectDB.

For each node the function extracts color, depth, confidence, the optimized world pose, and camera intrinsics in their original RTABMap format and stores everything in the project database. Images are stored in their native orientation without rotation.

No heavy processing (voxelization, normal estimation, etc.) is performed. Point cloud generation is handled separately by reusex::geometry::reconstruct_point_clouds().

Parameters
dbTarget project database (must be open in write mode).
rtabmap_db_pathPath to the source RTABMap .db file.

◆ interpolate_pose()

std::optional< std::array< double, 16 > > reusex::io::interpolate_pose ( const ArkitTrajectory & traj,
double ts,
double max_gap = kArkitMaxPoseGap )

Interpolate the camera->world pose at ts from the bracketing trajectory samples: SLERP on the rotation, linear interpolation on the camera position.

Interpolation is done on the camera->world pose (rather than the raw world->camera extrinsic) so the lerped translation is the camera's world position, which moves smoothly; lerping the world->camera translation -R·p would mix in the rotation and bend the camera path.

The depth stream (~60 Hz) is six times denser than the trajectory (~10 Hz), so nearest-pose matching would hand most frames a pose up to ~17 ms stale (tens of millimetres of lateral error at typical hand-held speeds); interpolating removes that temporal error.

Parameters
trajTimestamp-ascending trajectory (see load_arkit_trajectory).
tsQuery timestamp, in the trajectory's own time base.
max_gapReject if the bracketing samples are farther apart than this (tracking loss).
Returns
The interpolated row-major 4x4 pose, or std::nullopt if ts lies outside the trajectory's span or the bracketing gap exceeds max_gap. No extrapolation is performed.

References kArkitMaxPoseGap.

◆ load_arkit_trajectory()

ArkitTrajectory reusex::io::load_arkit_trajectory ( const std::filesystem::path & traj_path)

Parse the trajectory file into timestamp-sorted camera->world poses.

Each line is ts rx ry rz tx ty tz (world->camera; see arkit_traj_to_optical_world); unparseable and blank lines are skipped.

Exceptions
std::runtime_errorif the file yields no poses.

◆ make_rhino_mesh()

auto reusex::io::make_rhino_mesh ( const pcl::PolygonMesh & mesh) -> std::unique_ptr< ON_Mesh >

Convert a PCL PolygonMesh to an ON_Mesh.

◆ make_rhino_pointcloud() [1/2]

auto reusex::io::make_rhino_pointcloud ( CloudConstPtr cloud) -> std::unique_ptr< ON_PointCloud >

Convert a PCL XYZRGB point cloud to an ON_PointCloud.

◆ make_rhino_pointcloud() [2/2]

auto reusex::io::make_rhino_pointcloud ( CloudConstPtr cloud,
CloudNConstPtr normals ) -> std::unique_ptr< ON_PointCloud >

Convert a PCL XYZRGB point cloud with normals to an ON_PointCloud.

◆ make_sphere_mesh()

auto reusex::io::make_sphere_mesh ( double cx,
double cy,
double cz,
double radius,
int resolution = 16 ) -> std::unique_ptr< ON_Mesh >

Create a UV sphere mesh.

◆ parse_frame_timestamp()

bool reusex::io::parse_frame_timestamp ( const std::filesystem::path & file,
double & ts )

Extract the timestamp encoded in an ARKitScenes stream filename such as 41069021_452.395.png: drop the extension, then take everything after the last underscore (a bare std::stod would stop at the video-id prefix).

Returns
false if that substring is not a complete number.

◆ parse_pincam()

ArkitPincam reusex::io::parse_pincam ( const std::string & line)

Parse a single ARKitScenes .pincam line: width height fx fy cx cy (six whitespace-separated doubles).

Exceptions
std::runtime_errorif fewer than six numbers can be parsed.

◆ read()

bool reusex::io::read ( std::filesystem::path const & input_path,
std::vector< pcl::ModelCoefficients > & model_coefficients,
std::vector< Eigen::Vector4f, Eigen::aligned_allocator< Eigen::Vector4f > > & centroids,
std::vector< std::shared_ptr< pcl::Indices > > & inlier_indices )
nodiscard

Read plane data from file.

Parameters
input_pathPath to input file.
model_coefficientsOutput plane model coefficients.
centroidsOutput plane centroids.
inlier_indicesOutput indices of points belonging to each plane.
Returns
True if read was successful, false otherwise.

◆ read_exif_timestamp()

double reusex::io::read_exif_timestamp ( const std::filesystem::path & jpeg_path)

Read EXIF DateTimeOriginal from a JPEG file.

Returns epoch seconds (double), or -1.0 if not available.

◆ save()

bool reusex::io::save ( std::filesystem::path const & output_path,
std::vector< pcl::ModelCoefficients > const & model_coefficients,
std::vector< Eigen::Vector4f, Eigen::aligned_allocator< Eigen::Vector4f > > const & centroids,
std::vector< std::shared_ptr< pcl::Indices > > const & inlier_indices )
nodiscard

Save plane data to file.

Parameters
output_pathPath to output file.
model_coefficientsPlane model coefficients.
centroidsPlane centroids.
inlier_indicesIndices of points belonging to each plane.
Returns
True if save was successful, false otherwise.

Variable Documentation

◆ kArkitMaxPoseGap

double reusex::io::kArkitMaxPoseGap = 0.5
constexpr

Largest bracketing interval interpolate_pose will interpolate across.

The lowres_wide.traj stream is ~10 Hz (0.1 s spacing); a gap an order of magnitude larger means ARKit lost tracking, and interpolating across it would invent a pose, so such frames are rejected instead.

Definition at line 61 of file arkitscenes.hpp.

Referenced by interpolate_pose().