| | |
| | | export, or image sequence is copied unchanged into a raw run directory before a |
| | | console run is processed. |
| | | |
| | | The local console accepts 3-1000 JPG/JPEG photos per reconstruction run. The |
| | | same-flight and same-camera requirement still applies. CPU reconstruction is an |
| | | asynchronous job: a large sequence can take hours or longer, depending on image |
| | | resolution, overlap, and available storage; uploads and source images remain |
| | | byte-for-byte preserved. |
| | | |
| | | The console shows completed reconstruction milestones from the fixed sparse and |
| | | dense scripts, including feature extraction, matching, sparse mapping, RGB |
| | | preparation, undistortion, dense fusion, meshing, texture export, and final |
| | | artifact packaging. Its percentage is a weighted workflow-stage milestone, not |
| | | a remaining-time estimate, because COLMAP and OpenMVS do not provide reliable |
| | | live progress inside their individual native processing steps. |
| | | |
| | | The console permits this asynchronous CPU job to run for up to 24 hours before |
| | | reporting a timeout. This is a safety ceiling, not a runtime estimate. |
| | | |
| | | ```powershell |
| | | $py = .\.venvs\05-3d-pointcloud\Scripts\python.exe |
| | | & $py .\capabilities\05-3d-pointcloud\run_pointcloud_understanding.py ` |
| | |
| | | --threads 12 --max-resolution 2400 --dense-resolution-level 0 ` |
| | | --dense-number-views 8 --dense-number-views-fuse 2 --target-faces 800000 |
| | | ``` |
| | | |
| | | ### CPU and GPU compatibility |
| | | |
| | | Photo reconstruction does **not** require a GPU. The CPU route above is the |
| | | complete, verified baseline: image preparation, sparse SfM, dense MVS, meshing, |
| | | texturing, GLB export, and metadata all run locally on CPU. It is slower for |
| | | large or high-resolution photo sets, but it is the default route for any |
| | | computer and remains the console's only selectable reconstruction route. |
| | | |
| | | CUDA is an optional acceleration experiment for the OpenMVS dense depth/fusion |
| | | stage only. It does not move EXIF processing, image conversion, sparse SfM, |
| | | meshing, texturing, exports, or the local console to the GPU. Use it only with a |
| | | separately installed, compatible CUDA OpenMVS binary and an empty output |
| | | directory: |
| | | |
| | | ```powershell |
| | | & $py .\capabilities\05-3d-pointcloud\run_cpu_dense_reconstruction.py ` |
| | | --input <coherent-photo-directory> ` |
| | | --sparse-model <verified-sparse-model-directory> ` |
| | | --output <new-output-directory> ` |
| | | --openmvs-bin <cuda-openmvs-binary-directory> ` |
| | | --dense-device cuda |
| | | ``` |
| | | |
| | | CUDA is accepted only when the native OpenMVS log explicitly reports CUDA/GPU |
| | | execution; the run never silently falls back to CPU. `run_metadata.json` records |
| | | the requested and actual dense-MVS device. On this workstation, PyTorch CUDA is |
| | | available, but both tested official CUDA MVS binaries failed on the six-photo |
| | | validation set before depth-map output (OpenMVS: CUDA error 801; COLMAP: CUDA |
| | | device/context failure). Consequently CUDA MVS is not exposed in the console or |
| | | claimed as usable here. CPU MVS remains the supported path until a compatible |
| | | driver/toolchain combination or a validated server environment is available. |
| | | |
| | | The separate supervised point-cloud semantic-model training and inference flow |
| | | does support `auto`, `cpu`, and `cuda` in the local console. This applies only |
| | | to PyTorch model computation, not to photo reconstruction, point-cloud file I/O, |
| | | DSM/vector generation, or export. `auto` falls back to CPU with a recorded |
| | | reason; an explicit CUDA request fails when the fixed CUDA environment cannot |
| | | be verified. |
| | | |
| | | WebODM/ODX-compatible RTK input preparation (metadata only; it neither starts |
| | | WebODM nor reconstructs a model): |
| | |
| | | metric-accurate. Obtain registered source data and manually reviewed truth before |
| | | operational or commercial use. |
| | | |
| | | ## Photo, pose, and point-cloud multimodal preflight |
| | | |
| | | The planned `same-scene photo features + RGB/XYZ point cloud + Point Transformer |
| | | V3` route begins with a bounded, CPU-only compatibility check. It is B work: |
| | | Laspy, PyProj, OpenCV, Pillow, and NumPy verify ODM/OpenSfM camera data and |
| | | point-to-image projection. `geoai-py` has no built-in API for this workflow. |
| | | |
| | | The preflight requires a coloured LAS/LAZ with a declared CRS, original photos, |
| | | ODM/OpenSfM `cameras.json`, and `shots.geojson`. It validates exact filename |
| | | matching, normalises ODM's optional `v2` camera-name prefix, transforms every |
| | | shot GeoJSON WGS84 point into the LAS CRS, then compares it to the reported |
| | | camera-centre translation. It samples the LAS with bounded memory and projects |
| | | those points through the Brown camera model and OpenSfM Rodrigues pose. Source |
| | | photos, LAS data, and camera files remain unchanged. |
| | | |
| | | ```powershell |
| | | $py = .\.venvs\05-3d-pointcloud\Scripts\python.exe |
| | | & $py .\capabilities\05-3d-pointcloud\prepare_multimodal_pointcloud_dataset.py ` |
| | | --images .\baseData\img ` |
| | | --las .\baseData\las\Task-of-2026-08-22T084705607Z-georeferenced_model.las ` |
| | | --cameras .\baseData\camera\Task-of-2026-08-22T084705607Z-cameras.json ` |
| | | --shots .\baseData\camera\Task-of-2026-08-22T084705607Z-shots.geojson ` |
| | | --output .\shared\outputs\05-3d-pointcloud\multimodal-preflight-<new-run-id> |
| | | ``` |
| | | |
| | | The output contains `input_inventory.json`, `pose_projection_report.json`, |
| | | 12 representative `projection-overlays/*.jpg`, and `run_metadata.json`. The |
| | | acceptance gate requires no missing photo/shot pairs, a maximum WGS84-to-LAS |
| | | camera-centre XY residual at or below 0.25 m, and at least 50 sampled LAS points |
| | | inside every representative calibrated image frame. It proves data availability |
| | | only. A sparse red-point overlay is not an alignment acceptance artifact: it can |
| | | be in-frame while remaining visually unreadable or offset. |
| | | |
| | | Real preflight on 2026-08-25 used 550 original 4032 x 3024 DJI M4TD images, |
| | | the 75,870,130-point RGB `EPSG:32650` LAS export, one Brown calibration, and |
| | | 550 shots. All filenames matched. The maximum 550-shot WGS84-to-UTM camera |
| | | centre XY residual was 0.0 m. From a deterministic 120,000-point bounded LAS |
| | | sample, all 12 distributed diagnostic photos passed the in-frame check (minimum |
| | | 17,319; median 34,403 sampled points). The artefacts are in |
| | | `shared/outputs/05-3d-pointcloud/multimodal-preflight-20260825-550-photos/`. |
| | | This is not yet a feature fusion, semantic label, occlusion, or accuracy result. |
| | | |
| | | The second diagnostic uses the same pose data but renders a deterministic |
| | | one-million-point RGB LAS sample through a closest-point z-buffer. It compares |
| | | the current ODM pose convention with an inverse-rotation negative control, |
| | | checks the derived viewing axis against the DJI XMP gimbal yaw/pitch, and writes |
| | | three inspectable PNGs per representative image: point-only RGB, |
| | | photo/point-RGB blend, and point/edge overlay. It automatically detects whether |
| | | LAS RGB values are effectively 8-bit or 16-bit; LAS dimensions alone are not a |
| | | reliable colour-scale indicator. |
| | | |
| | | ```powershell |
| | | & $py .\capabilities\05-3d-pointcloud\diagnose_multimodal_projection.py ` |
| | | --images .\baseData\img ` |
| | | --las .\baseData\las\Task-of-2026-08-22T084705607Z-georeferenced_model.las ` |
| | | --cameras .\baseData\camera\Task-of-2026-08-22T084705607Z-cameras.json ` |
| | | --shots .\baseData\camera\Task-of-2026-08-22T084705607Z-shots.geojson ` |
| | | --output .\shared\outputs\05-3d-pointcloud\multimodal-projection-diagnostic-<new-run-id> |
| | | ``` |
| | | |
| | | On 2026-08-26, three distributed images passed this stronger check. The current |
| | | rotation has median RGB MAE 30.501, versus 60.612 for inverse rotation, and a |
| | | 48.5% median improvement over shuffled pixel locations. Its median DJI gimbal |
| | | view-axis difference is 0.647 degrees. The screenshot image `0450` has RGB MAE |
| | | 23.641, correlation 0.7529, and 60.53% improvement over shuffled locations; |
| | | its inverse rotation correlation is 0.0306. The result is stored at |
| | | `shared/outputs/05-3d-pointcloud/multimodal-projection-diagnostic-20260826-v2/`. |
| | | This accepts the current pose convention for photo-feature projection, but does |
| | | not claim sub-pixel calibration, complete visibility/occlusion filtering, or |
| | | semantic model accuracy. |
| | | |
| | | ## Multi-view visibility and feature fusion |
| | | |
| | | `prepare_multiview_point_features.py` is the next CPU-only data-preparation |
| | | step for the planned multimodal semantic workflow. It selects a bounded LAS |
| | | sample, projects each point into a selected set of verified ODM photos, and |
| | | uses a two-pixel closest-depth z-buffer to reject points hidden behind another |
| | | point in the same image cell. For each remaining observation it gathers eight |
| | | deterministic visual descriptors: photo RGB, hue sine/cosine, saturation, |
| | | gradient magnitude, and local-intensity standard deviation. Each point stores |
| | | the multi-view mean and standard deviation separately from its original |
| | | `XYZ + LAS RGB`, plus its valid-view count. |
| | | |
| | | ```powershell |
| | | & $py .\capabilities\05-3d-pointcloud\prepare_multiview_point_features.py ` |
| | | --images .\baseData\img ` |
| | | --las .\baseData\las\Task-of-2026-08-22T084705607Z-georeferenced_model.las ` |
| | | --cameras .\baseData\camera\Task-of-2026-08-22T084705607Z-cameras.json ` |
| | | --shots .\baseData\camera\Task-of-2026-08-22T084705607Z-shots.geojson ` |
| | | --output .\shared\outputs\05-3d-pointcloud\multiview-feature-<new-run-id> ` |
| | | --max-points 50000 --max-shots 550 --z-buffer-cell-size 2 |
| | | ``` |
| | | |
| | | The run creates `multiview-point-features.npz`, a coverage-coloured PLY, an |
| | | ordered original-RGB `multiview-annotation-source.ply`, per-photo visibility |
| | | CSV, coverage JSON, and metadata. The compressed NPZ has |
| | | `xyz`, `las_rgb`, `photo_feature_mean`, `photo_feature_stddev`, |
| | | `visible_view_count`, and ordered `feature_names` arrays. It intentionally has |
| | | no semantic class field or pseudo-label. |
| | | |
| | | The annotation PLY never uses the coverage pseudo-colours. Its vertex `i` is |
| | | the same `xyz[i]` / `las_rgb[i]` row in the NPZ, and `run_metadata.json` records |
| | | both SHA-256 values and the point count. The local console exposes it only when |
| | | the PLY header, both NPZ array lengths, declared file names, and checksums all |
| | | match. This prevents a display preview or an incomplete fusion directory from |
| | | becoming a label source. To add this source once to an older completed fusion |
| | | run without recomputing photo features: |
| | | |
| | | ```powershell |
| | | & $py .\capabilities\05-3d-pointcloud\prepare_multiview_point_features.py ` |
| | | --output .\shared\outputs\05-3d-pointcloud\multiview-feature-<completed-run-id> ` |
| | | --annotation-source-only |
| | | ``` |
| | | |
| | | Real CPU verification on 2026-08-26 processed 50,000 deterministic LAS sample |
| | | points against all 550 photos in 899.880 seconds. Every point had an occlusion- |
| | | filtered observation; all had at least two and at least three valid views, and |
| | | 99.978% had at least ten. The mean and median valid-view counts were 147.2697 |
| | | and 154 respectively, with 235 maximum. All visual-feature arrays were finite; |
| | | the feature standard-deviation mean was 0.140754 and p95 was 0.320565. The |
| | | result is in `shared/outputs/05-3d-pointcloud/multiview-feature-550-photo-sample-20260826/`. |
| | | |
| | | This validates the fusion format and observation coverage only. The z-buffer |
| | | is not a full physical visibility model, and these descriptors are not a |
| | | pretrained photo encoder. A chunked full 75,870,130-point preparation should |
| | | only start after reviewed semantic labels and the spatial training/validation/ |
| | | test split are agreed; then the deterministic descriptors can be replaced or |
| | | augmented with a GPU photo encoder before Point Transformer V3 training. |
| | | |
| | | ## Semantic point-cloud classification baseline |
| | | |
| | | The existing-point-cloud route now writes a separate CPU semantic-classification |
| | |
| | | Classes are `ground`, `vegetation`, `building_structure`, `power_line`, |
| | | `pole_tower`, and `other_unknown`. The last three names describe review outputs: |
| | | the first version is deliberately a transparent rule baseline rather than a |
| | | trained semantic model. It exports a colour-coded preview PLY (capped at 400,000 |
| | | points for the browser), semantic LAS class codes, class GeoTIFF/PNG, candidate |
| | | trained semantic model. It exports a colour-coded preview PLY containing the |
| | | complete processed point set, semantic LAS class codes, class GeoTIFF/PNG, candidate |
| | | GeoJSON, class-count CSV, and `run_metadata.json`. |
| | | |
| | | Real LAS check: the unchanged user input `baseData/las/part_01.las` contains |
| | |
| | | ## Human annotation and supervised GPU/CPU training |
| | | |
| | | The workbench now provides a separate human annotation and supervised training |
| | | area. A semantic run writes a 400,000-point `*.semantic-annotation-source.ply` |
| | | area. A semantic run writes a complete processed `*.semantic-annotation-source.ply` |
| | | that preserves observed RGB and coordinates. Rule-coloured previews are never |
| | | used as model inputs or ground truth. Brush and rectangle selections are saved |
| | | as separate revisions under `shared/outputs/05-3d-pointcloud/annotations/<annotation-id>/`. |
| | | The annotation viewer renders observed RGB through an sRGB-correct, anti-aliased |
| | | circular point sprite. It separates navigation from annotation: browse mode |
| | | uses left-drag rotation, while brush/rectangle mode reserves left-drag for |
| | | labels and retains right-drag rotation, middle-drag panning and wheel zoom. |
| | | The annotation viewer renders observed RGB through an sRGB-correct, anti-aliased |
| | | circular point sprite. It separates navigation from annotation: browse mode |
| | | uses left-drag rotation, while brush/rectangle mode reserves left-drag for |
| | | labels and retains right-drag rotation, middle-drag panning and wheel zoom. |
| | | The console displays every point in the selected annotation source directly. |
| | | It does not replace the view with a zoom-dependent local layer, so point indices |
| | | remain stable for browsing, brush/rectangle labels, saved revisions, and |
| | | training. Large sources require correspondingly more browser memory and GPU |
| | | resources. |
| | | |
| | | ### Automatic annotation review loop |
| | | |
| | | After a completed local model is selected, **Automatic annotation current |
| | | source** runs that fixed local model against the selected source without a second |
| | | upload. It writes an immutable candidate record with the source/model SHA-256, |
| | | per-point confidence, per-class candidate counts and a user-selected confidence threshold. The console renders a separate class-coloured prediction viewer for review alongside the RGB annotation source. In that viewer, brush/rectangle review can reject a candidate or correct it to another class; its saved correction draft remains separate from human truth. **Confirm merge candidates** applies candidate labels, then the saved review draft, then existing human labels (highest priority), and creates a new |
| | | annotation revision only after explicit confirmation; existing human labels win |
| | | when they overlap model candidates. That new revision can be used for the next |
| | | training run. This is an assisted-labelling workflow, not a claim that the model |
| | | has created ground truth. The candidate preview and confidence JSON must be |
| | | reviewed before acceptance, especially for classes with weak or absent spatial |
| | | test evidence. |
| | | New annotation uploads use a separate CPU preview preparation step rather than |
| | | the DSM/footprint pipeline: it only reads XYZ and available vertex RGB, then |
| | | writes every readable finite XYZ point and available vertex RGB value. It therefore does |
| | | not create rasters, vectors, or meshes and is unaffected by a source cloud's |
| | | spatial extent. A textured-mesh PLY without readable per-vertex RGB is shown |
| | | with neutral points for geometry review, but is explicitly ineligible for the |
| | | current RGB semantic-model trainer. |
| | | |
| | | ### Textured mesh RGB baking |
| | | |
| | | Some PLY files are textured triangle meshes rather than RGB point clouds. They |
| | | store only vertex XYZ plus per-face UV coordinates and `TextureFile` image |
| | | references, so a point viewer cannot recover colour from the PLY alone. The |
| | | CPU-only `bake_textured_mesh_pointcloud.py` reads one ZIP bundle containing the |
| | | PLY and all referenced JPG/PNG texture tiles, samples each selected triangle's |
| | | UV centroid with a vertical texture-axis correction, and writes a binary |
| | | `XYZ + RGB` PLY. Its points represent sampled triangle-face centres, not the |
| | | original vertices. This is B work using NumPy/Pillow/PLY parsing, not a native |
| | | `geoai-py` point-cloud API. |
| | | |
| | | ```powershell |
| | | & .\.venvs\05-3d-pointcloud\Scripts\python.exe ` |
| | | .\capabilities\05-3d-pointcloud\bake_textured_mesh_pointcloud.py ` |
| | | --input E:\DJI\PLY\南航\PLY\Model_0.zip ` |
| | | --output .\shared\outputs\05-3d-pointcloud\texture-baked-<run-id> ` |
| | | ``` |
| | | |
| | | The representative `Model_0.zip` check on 2026-08-28 contained one 7,430,655 |
| | | vertex / 14,820,237 face PLY and 141 texture images. The 50,000-face sample |
| | | used 140 referenced texture images and completed CPU baking in 174.921 seconds. |
| | | Its RGB standard deviation was `[62.5, 58.0, 65.0]` and 80.17% of points had |
| | | materially non-grey channel differences, confirming that texture RGB rather |
| | | than placeholder grey was written. Visual UV alignment still needs user review |
| | | before a complete annotation/training source is generated. |
| | | Middle-button auto-scroll is suppressed within the viewer. The rotate-centre |
| | | tool sets the camera target to a clicked visible point without creating a label. |
| | | The model-orientation control independently rotates the displayed model about |
| | | its centre on local X/Y/Z axes from 0 through 360 degrees. It is a viewer-only |
| | | transform: source coordinates, semantic outputs and saved point indices remain |
| | | unchanged, while point picking and rectangle selection use the transformed view. |
| | | |
| | | The sparse SfM, semantic-classification, supervised-prediction, and mesh |
| | | preview panels share these display-only X/Y/Z orientation controls, a click-to- |
| | | set orbit centre, top-down view, and view reset. They do not alter source PLY, |
| | | GLB, LAS, semantic output, annotation index, or downloaded artifact bytes. |
| | | A saved revision is never edited in place. If it contains an error, the console |
| | | can remove that selected revision after confirmation; it cannot delete source |
| | | LAS/PLY data, semantic results, or training outputs. Each revision records |
| | | source run/checksum, point indices, class codes and time. |
| | | |
| | | The **Annotation, training, and model application** workspace also provides |
| | | **Add annotation source** and **Manage annotation classes**. Add source accepts |
| | | one local PLY/PCD/XYZ/LAS/LAZ through the bounded binary upload endpoint. It |
| | | preserves the exact original bytes under the point-cloud raw-data layout, then |
| | | runs a background CPU job to create a separate RGB/XYZ annotation preview; no |
| | | existing source is overwritten. The local taxonomy starts with ground, |
| | | vegetation, building, pole/tower, power line, and other/unknown. A user can add |
| | | a Chinese display name, lowercase English key, and RGB colour; the console |
| | | assigns a distinct LAS-compatible class code from 1-255. Each saved annotation |
| | | snapshots its complete class definitions. A custom class used by any saved |
| | | revision cannot be deleted, so historical labels and trained model metadata |
| | | remain interpretable. Adding a source or category creates no semantic truth by |
| | | itself: reviewed spatially distributed labels are still required for training. |
| | | |
| | | The selected annotation source also has **Remove complete data chain**. Before |
| | | the irreversible confirmation, the local server calculates and displays the |
| | | actual number of generated output directories, raw-upload copies, processed |
| | | copies, annotation revisions, dependent training results, and model-inference |
| | | results. Confirming removes those local workbench artifacts in dependency order. |
| | | It never accepts a browser-supplied filesystem path and never removes |
| | | `baseData` imagery, LAS, camera files, or any other external input. When an |
| | | older derived source has no console-owned raw copy, only its generated output |
| | | chain is removed and the confirmation says that the external input is retained. |
| | | |
| | | The model workspace also discovers a completed `multiview-feature-*` fusion |
| | | directory as `多视角照片特征融合样本` when its ordered original-RGB PLY, NPZ and |
| | | checksum contract pass. Its 50,000-point current sample is a human-review entry |
| | | until it has reviewed labels. Its automatic training entry selects |
| | | `train_multiview_point_transformer.py`, which reads only the checksum-linked |
| | | same-order NPZ and uses 23 inputs per point: normalized XYZ, LAS RGB, eight |
| | | photo-feature means, eight photo-feature standard deviations, and normalized |
| | | visible-view count. It constructs 16 local geometric neighbours and trains a |
| | | two-stage local point-attention baseline with complete XY-block train, |
| | | validation, and test separation. It writes `model.pt`, `metrics.json`, |
| | | `run_metadata.json`, and a colour-coded `predicted-semantic-preview.ply`. |
| | | |
| | | This model is explicitly **not** official Point Transformer V3 or Pointcept. |
| | | The Pointcept/PTv3 dependency stack (`spconv` and related CUDA extensions) is |
| | | not installed or validated on this machine, so the workbench does not make that |
| | | claim. The baseline is CPU-compatible and can use CUDA only after the fixed |
| | | PyTorch CUDA environment passes its probe. It cannot classify an arbitrary |
| | | uploaded point cloud because that input would lack matching camera poses and |
| | | multi-view photo descriptors. |
| | | |
| | | Training requires at least two reviewed classes with 500 points per class, and |
| | | each class must appear in training, validation, and test XY blocks. For the |
| | | current sample, label vegetation, pole/tower, and power line in multiple |
| | | separated areas before clicking `多视角特征训练`. The retained checkpoint is |
| | | selected by validation macro F1; metrics apply only to reviewed source blocks |
| | | and are not field-wide accuracy or inspection evidence. |
| | | |
| | | `train_pointcloud_semantic_model.py` trains a compact PointNet-style shared MLP |
| | | from user-confirmed labels only. It accepts `--device auto`, `cpu`, or `cuda`; |
| | |
| | | 1.554 seconds and records `processing.device: "cuda"` in `run_metadata.json`. |
| | | This is a local labelled-block comparison only; it does not establish field-wide |
| | | accuracy or authorise asset/inspection conclusions. |
| | | |
| | | ## Console result lifecycle |
| | | |
| | | The local console treats every console-owned point-cloud case as a complete |
| | | result chain. Before removal, it obtains a server-calculated plan and requires a |
| | | second confirmation. A removable case is limited to |
| | | `shared/outputs/05-3d-pointcloud/runs/<run-id>/` and its fixed console raw and |
| | | processed copies; `baseData`, external inputs, validation/baseline assets, and |
| | | unrelated runs are preserved. The point-cloud training-model selector separately |
| | | removes the chosen local training directory and only its discovered model |
| | | inference and automatic-annotation outputs. It preserves annotation revisions |
| | | so reviewed labels are never discarded merely because a model is removed. |