Documentation menu

Horus Vertex

Deliveries from the Horus Vertex mobile-mapping system, exported through Horus Movie Maker. One folder per recording, each carrying pre-stitched panoramas and the raw lidar capture — the coloured point cloud is produced here rather than delivered.

Folder layout#

<dataset bucket>/
├── 2026_05_07_10_34_40_Deventer_Deel1/     one folder per recording
│   ├── panorama/
│   │   ├── export.csv                      Movie Maker pose export
│   │   └── jpg/
│   │       ├── 0.jpeg                      pre-stitched equirectangular
│   │       └── 1.jpeg
│   └── lidar/
│       ├── capture.pcap                    Hesai XT32M2X capture
│       ├── trajectory.txt                  Applanix export
│       └── mission.log                     carries the mission date
└── 2026_05_07_11_02_48_Deventer_Deel2/
    └── …

Recording folders sit at the bucket root — there is no ingest/ wrapper — and are recognised by their contents, not their name: any root folder that directly contains a panorama/ or lidar/ subfolder is a recording. Movie Maker names folders by the capture timestamp, and keeping that is good practice (it sets the processing order), but nothing depends on it. The folder name becomes the set name, so it is what people will see in the viewer.

A root folder that is neither a recording nor a platform output (pointcloud/, copc/) is reported and skipped. A delivery with no recording folder at the root fails.

Inside a recording#

PathRequiredNotes
panorama/*.csvfor indexingExactly one is read: the alphabetically first CSV directly inside panorama/. A recording with none is skipped with a note and its photos are not indexed
panorama/jpg/*.jpegyesPre-stitched equirectangular panoramas. .jpg is accepted too
lidar/*.pcapfor the point cloudOne or more. A recording with none is panorama-only — it is not an error, and shows in the run as a skipped recording
lidar/*.txtwith a .pcapThe Applanix trajectory export
lidar/*.logwith a .pcapRead for the mission date

A delivery where no recording has a .pcap fails. A Vertex rig always captures lidar, so that state means a broken delivery or the wrong bucket — it is caught rather than quietly producing a panorama-only dataset.

Files we write back#

Two things appear in your bucket that you did not deliver, and neither should be removed by a subsequent upload:

  • <recording>/lidar/trajectory.360traj — the resolved trajectory.
  • <recording>/recording_done — a marker written last, after every output for that recording is durable.

The marker is what makes re-running cheap: a recording that already has one is skipped rather than reprocessed. To force a recording to be processed again, delete its recording_done. See Re-running is safe.

The pose CSV#

SeparatorComma
PreambleThe first 2 lines are skipped, then a header row, then data
ColumnsAddressed by name, case-insensitively. Order does not matter
Extra columnsIgnored
DecimalsBoth . and , accepted
Photo namesMatched with .jpeg appended, then with .jpg appended — first hit wins; case-sensitive
Which fileThe alphabetically first .csv directly inside panorama/
ColumnTypeMeaning
FrametextPhoto name without extension — resolves to panorama/jpg/<Frame>.jpeg, falling back to .jpg
LongitudenumberDegrees — see CRS
LatitudenumberDegrees
AltitudenumberEllipsoidal height in metres, not orthometric
HeadingnumberCompass heading, degrees
PitchnumberDegrees
RollnumberDegrees
StamptimestampCapture time

Ragged rows are tolerated — rows may have differing field counts. The two skipped preamble lines are part of the Movie Maker export — do not strip them, and do not add a third.

Stamp accepts any of: epoch seconds (whole or fractional); RFC 3339 (2026-05-07T09:18:00Z); YYYY-MM-DD HH:MM:SS[.fff] (read as UTC); YYYY-MM-DDTHH:MM:SS[.fff] (read as UTC); YYYY/MM/DD HH:MM:SS[.fff] (read as UTC); DD-MM-YYYY HH:MM:SS[.fff] (read as Dutch local time, Europe/Amsterdam); YYYY-MM-DD (UTC midnight).

These are the same formats Mobile mapping generic accepts; the unzoned shapes are read as UTC.

Coordinate reference system#

This template reprojects, unlike most. Positions are delivered as geographic coordinates in EPSG:4937 (ETRS89, 3D) and transformed into the dataset's configured CRS on ingest.

So Longitude / Latitude are degrees and Altitude is an ellipsoidal height — not NAP, and not a projected easting/northing. Delivering RD coordinates in these columns places the data far out to sea.

This is an exception to the general rule; see Coordinates are not reprojected.

See Rotation angles.

Tolerance#

Applied per recording, so one bad recording does not sink the rest:

  • Up to 10 % of a recording's CSV rows may reference missing photos. Beyond that the run fails, naming the recording.
  • Photos in the delivery that the CSV does not reference are not indexed (noted, not an error).
  • A recording with no CSV under panorama/ → not indexed, with a note.
  • A recording with no .pcap → panorama-only, no point cloud. Not an error.
  • A recording that already carries recording_done → skipped.

And the delivery as a whole must hold together:

  • At least one recording must contain lidar captures. A Vertex rig always records lidar, so a delivery where every recording folder lacks a .pcap is a broken delivery or the wrong bucket.
  • A recording with .pcap files must also carry its trajectory: exactly one POSPac export .txt in lidar/ (or an already-converted trajectory.360traj). Multiple .txt files are ambiguous and fail the recording.
  • A recording with .pcap files must also carry the Movie Maker pose CSV — the point cloud is coloured from the panoramas, which need their poses.
  • Every delivered photo must start with a JPEG marker and end with an end-of-image marker. This catches a file that is not a JPEG whatever its extension says, and the truncated upload — which a size check cannot see, because a truncated file just looks smaller and nothing knows how big it should have been.

Ingest parameters#

KeyRequiredTypeMeaning
anonymisationyesstring — recognised: already_anonymised, auto_anonymiseCompared exactly: already_anonymised marks the photos as already blurred, auto_anonymise queues them for blurring, any other value does neither.
height_above_groundyesnumberCamera height above the road surface, in metres.
vehicle_identifieryesstringThe identifier of the capturing rig, as registered with the platform.

All three are checked before any recording is processed, so a missing parameter fails immediately rather than part-way through a long run.

vehicle_identifier must name a rig we hold a record for under this ingest profile, and that rig must have at least one calibration on file. Both are verified up front, with a message saying which is missing. If you are capturing with a rig for the first time, its calibration has to be registered before the first delivery — talk to us before you upload.

What you get back#

  • Indexed panoramas per recording, with positions and orientations.
  • A tilepack (.tpc) per photo. Omnibase tenants view the JPEG; DZP is not generated at ingest.
  • Blurred derivatives, if anonymisation is auto_anonymise.
  • One coloured point cloud per recording at pointcloud/<recording>.laz, built from the lidar capture, georeferenced against the trajectory and coloured from that recording's own panoramas.
  • A single merged COPC at copc/pointcloud.copc.laz, which is what the web viewer streams.

You deliver raw captures; the coloured cloud is an output, not an input.

Common failures#

SymptomCause
"no recording folders at the bucket root"The recordings are nested under ingest/ or another wrapper — a recording folder must sit at the root with panorama/ or lidar/ directly inside it
"all N recording folders have no .pcap"The lidar captures were not uploaded, or they are not under <recording>/lidar/
A recording indexed with no point cloudThat recording has no .pcap — it was treated as panorama-only
A recording's photos missing entirelyNo CSV directly inside its panorama/ folder
More than 10 % of photos missingFrame values do not match the files in panorama/jpg/, or the photos are in a subfolder of it
"unknown vehicle_identifier"The rig is not registered under this ingest profile
"has no calibration rows"The rig is registered but not yet calibrated
Data far out to seaProjected coordinates were delivered where degrees are expected
A recording not reprocessed after a re-uploadIts recording_done marker is still there — delete it