Skip to content
यह पृष्ठ अभी आपकी भाषा में उपलब्ध नहीं है। अंग्रेज़ी संस्करण दिखाया जा रहा है।

3D Point Clouds and Cuboids

Annotate PCD, PLY, LAS and KITTI point clouds with oriented 3D cuboids, points, polylines and per-point segments. Octree level of detail, slab panels, and quaternion rotation that survives a round trip.

Potato annotates lidar and photogrammetry point clouds with oriented 3D cuboids, points, polylines and per-point segments, in the browser. Octree level of detail keeps a multi-million-point scan interactive on a laptop, and camera calibration projects every box into the images so you can verify in 2D while editing in 3D.

yaml
annotation_schemes:
  - annotation_type: spatial_annotation
    name: objects
    description: "Put a 3D box around every vehicle and pedestrian."
    source_field: point_cloud
    tools: [cuboid_3d, point_3d]
    labels:
      - {name: car, color: "#FF6B6B", key_value: "1"}
      - {name: pedestrian, color: "#FFD93D", key_value: "2"}
    color_mode: height
    point_size: 2.0
    max_points: 400000

Runnable example: examples/spatial/kitti-cuboids/.

Formats

Clouds are read server-side and converted into one compact binary the browser understands. Parsing each format in JavaScript would mean four parsers, four sets of endianness and record-layout bugs, and re-parsing a two-million-point scan on every page load.

FormatNotes
KITTI velodyne .binRaw float32 x, y, z, intensity, no header
PCDascii, binary, and binary_compressed (LZF)
PLYascii, binary_little_endian, binary_big_endian
LAS1.0 to 1.4, point record formats 0 to 3 and 6 to 8
.xyz / .ptsx y z [r g b] per line
LAZNot read directly. Convert first: laszip -i scan.laz -o scan.las

Colour is read where a format carries it; intensity is read from KITTI, PCD and LAS. Asking for color_mode: rgb on a file with no colour falls back to height and says so in the status line, rather than quietly rendering something that looks like the mode you asked for.

Tools

ToolWhat it draws
cuboid_3dAn oriented 3D box
point_3dA single 3D point
polyline_3dA path through the cloud
segment_3dA per-point label over a selected set

Rotation is a quaternion, not a yaw angle

Potato stores a cuboid's rotation as a full quaternion. Most formats store a single yaw, so this looks like over-engineering until a round trip loses something.

It is what makes KITTI import lossless, including the roughly 0.85° camera-to-lidar mounting tilt that a yaw-only field discards without saying so. Exporting back to KITTI does have to drop pitch and roll — and it reports how much orientation it discarded rather than silently flattening the box.

The gap between what Potato can represent and what a format can store is crossed in the format-specific code, loudly, rather than in the storage layer, silently.

Agreement uses exact rotated 3D IoU

Two annotators boxing the same car will not produce the same box. Potato computes agreement with exact rotated 3D IoU, which is correct under arbitrary rotation rather than only for axis-aligned boxes.

That matters as soon as the data is not level: drone, handheld and indoor scans all produce boxes with real pitch and roll, and an axis-aligned approximation reports disagreement that is an artefact of the measure rather than of the annotators. See geometry agreement.

Working at scale

  • Octree level of detail is on by default (lod: true). Points load by region and by distance, so a large scan stays interactive.
  • max_points caps decimation. It is a viewer setting, not a data setting.
  • Orthographic slab panels (mpr: true) give three axis-aligned views for precise, fully keyboard-driven editing. Drag one face while the opposite stays fixed.

One bug worth knowing about, since it affected stored data rather than display: segment_3d point indices used to assume a fixed decimation, so lowering max_points silently re-pointed existing per-point labels at different points. Indices now refer to the source file, so a viewer setting cannot move an annotation.