| | |
| | | return model, codes, classes |
| | | |
| | | |
| | | def write_prediction_preview(path: Path, xyz: np.ndarray, predictions: np.ndarray, class_schema: dict[int, dict[str, Any]]) -> None: |
| | | """Write display RGB plus stable LAS-compatible labels for the review viewer.""" |
| | | colors = np.asarray([class_schema[int(code)]["color"] for code in predictions], dtype=np.uint8) |
| | | records = np.empty(len(xyz), dtype=[("x", "<f4"), ("y", "<f4"), ("z", "<f4"), ("red", "u1"), ("green", "u1"), ("blue", "u1"), ("classification", "u1")]) |
| | | records["x"], records["y"], records["z"] = xyz[:, 0], xyz[:, 1], xyz[:, 2] |
| | | records["red"], records["green"], records["blue"] = colors[:, 0], colors[:, 1], colors[:, 2] |
| | | records["classification"] = predictions |
| | | header = ( |
| | | "ply\nformat binary_little_endian 1.0\n" |
| | | f"element vertex {len(records)}\n" |
| | | "property float x\nproperty float y\nproperty float z\n" |
| | | "property uchar red\nproperty uchar green\nproperty uchar blue\n" |
| | | "property uchar classification\nend_header\n" |
| | | ).encode("ascii") |
| | | with path.open("wb") as stream: |
| | | stream.write(header) |
| | | records.tofile(stream) |
| | | |
| | | |
| | | def main() -> int: |
| | | parser = argparse.ArgumentParser(description="Apply a local point-cloud semantic model to a new RGB point cloud.") |
| | | parser.add_argument("--model", type=Path, required=True) |
| | |
| | | |
| | | args.output.mkdir(parents=True, exist_ok=True) |
| | | preview_selection = np.arange(len(predictions), dtype=np.int64) |
| | | preview = o3d.geometry.PointCloud() |
| | | preview.points = o3d.utility.Vector3dVector(xyz[preview_selection]) |
| | | preview.colors = o3d.utility.Vector3dVector(np.asarray([class_schema[int(code)]["color"] for code in predictions[preview_selection]], dtype=np.float64) / 255.0) |
| | | preview_path = args.output / "predicted-semantic-preview.ply" |
| | | if not o3d.io.write_point_cloud(str(preview_path), preview, write_ascii=False): |
| | | raise RuntimeError("Could not write predicted PLY preview.") |
| | | write_prediction_preview(preview_path, xyz[preview_selection], predictions[preview_selection], class_schema) |
| | | |
| | | classified_las = args.output / "predicted-semantic-classified.las" |
| | | if source_las is not None: |