labelCloud: 3D Bounding Box Labeling in Point Clouds Without a Pipeline
A lightweight tool for labeling 3D bounding boxes in point clouds.
At a glance
- What is it?
- labelCloud is a Python tool for drawing 3D bounding boxes in point clouds, with two labeling modes and several export formats. Its value is that it stays small and configurable, and its limits follow from the same choice.
- Who is it for?
- Adopt labelCloud if you need to produce 3D box labels from point clouds on a single workstation and you want the label format to match an existing convention rather than a vendor's. Do not adopt it if you need multi-annotator review, a hosted labeling service, or a format that is not among the exporters listed in the README.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 137 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What labelCloud is for and who ends up using it
Point clouds arrive without labels. If you want to train a 3D object detector or estimate 6D pose, someone has to draw boxes around objects in three dimensions, and that someone needs a viewer that can rotate, zoom and translate through the scene. labelCloud is that viewer plus a labeling layer. The README describes it as "a lightweight tool for labeling 3D bounding boxes in point clouds," and the repository topics list 3d-object-detection, 6d-pose-estimation, annotation and point-clouds.
The intended user is an engineer or researcher preparing their own dataset, not a team running a large annotation operation. The setup instructions assume one person on one machine: clone the repository, install requirements, copy point clouds into a pointclouds folder, run python3 labelCloud.py. There is no server, no account system, and no mention of multiple annotators working on the same file. That narrows the audience in a way worth stating plainly. If your workflow assumes a queue of labeling tasks and a review step, labelCloud is the wrong shape of tool.
Picking and spanning: the two ways a box gets drawn
labelCloud offers two labeling methods, and they are genuinely different interactions rather than cosmetic variants.
In Picking Mode you pick the location of the bounding box at its front-top edge, then adjust the z-rotation by scrolling the mouse wheel. The box is effectively anchored at a point and then rotated into place. In Spanning Mode you span the length, width and height by selecting four vertices. The README notes that the layers for the last two vertices (width and height) are locked to allow easy selection, which is the interesting detail here: spanning a box in three dimensions from a 2D view is ambiguous, and locking the depth layer removes one degree of ambiguity from the click.
After the initial box exists, correction happens through buttons on the left-hand side or through shortcuts. Translation, dimension and rotation are each adjustable. Resizing works by holding the cursor above one side of the box and scrolling. The keyboard mapping is idiosyncratic enough to be worth reading before you start: W, A, S, D translate the box back, left, front and right, and Ctrl plus the right mouse button translates it in all dimensions. Camera control is separate, with the left mouse button rotating the camera around the point cloud centroid, the right button translating the camera, and the wheel zooming.
The default is z-rotation only. The README states that x- and y-rotation of bounding boxes are prohibited by default, and that labeling 9 DoF bounding boxes requires deactivating z-Rotation Only Mode in the menu, the settings, or config.ini. This default is a real design decision, not a hidden setting. Most ground vehicles on a road plane need only yaw, so the default keeps the interaction simple and prevents accidental tilt. If your objects can be oriented arbitrarily, you will be fighting the default until you find that toggle.
Import formats, export formats, and the exporter base class
The import table splits into colored and colorless formats. Colored: pcd, ply, pts and xyzrgb. Colorless: xyz, xyzn and bin in the KITTI layout. That is a reasonable spread, but it is a fixed list. A proprietary format from a specific sensor vendor is not on it, and the README does not describe an import plugin mechanism comparable to the exporter one.
Export is where the project shows its design intent. Five label formats ship: centroid_rel (centroid, dimensions, relative Euler angles in radians from -pi to +pi), centroid_abs (same but absolute Euler angles in degrees from 0 to 360), vertices (the eight corners of the box), kitti, and kitti_untransformed. The kitti format requires calibration files, and kitti_untransformed is the same structure without the transformations, for cases where you only want the label layout. The README also notes that all rotations are counterclockwise, so a z-rotation of 90 degrees is from the positive x-axis to the negative y-axis. That convention sentence matters more than it looks. Rotation sign and direction are the classic source of silently wrong training data.
The extensibility path is explicit: subclass the abstract BaseLabelFormat class in labelCloud/label_formats/base.py to build your own exporter. Import does not get the same treatment in the documentation. If your pipeline needs a format outside the table, you are reading source rather than following a guide.
Bounding-box-based semantic segmentation and its file format
Beyond boxes, labelCloud can produce segmentation labels derived from them. The mode is toggled in the startup dialog. You label as usual, and then press the Assign button whenever all points inside the current bounding box should receive the current class.
This is box-driven segmentation, which is a specific and limited idea. It assumes the object is well approximated by the box you drew and that every point inside that box belongs to the class. That holds for a car or a crate. It does not hold for a pedestrian with a bicycle, a tree canopy, or anything where the box contains a large amount of background. The README does not describe any per-point refinement tool, so the box boundary is the segmentation boundary.
The output goes to labels/segmentation/ as bin files. Each file holds an array with shape (number of points, ) and dtype np.int8, where each entry is the index of the label of the corresponding point in the original point cloud. Two constraints follow directly from that description. First, np.int8 caps you at a small number of classes, well under a hundred. Second, the array is positional, so it is tied to the point ordering of the input cloud. Reorder or subsample the cloud and the label file no longer lines up. That is an implicit coupling the README states through the format rather than as a warning.
Getting it running and what the config files control
There are two installation paths. The PyPI path is two commands: pip install labelCloud, then labelCloud --example to start with an example point cloud. The manual path is four steps: git clone the repository, pip install -r requirements.txt, copy point clouds into the pointclouds folder, and run python3 labelCloud.py. The README states that labelCloud currently supports Python 3.9 through 3.12, so a 3.8 environment is out of scope without checking.
Configuration is split across three places, and knowing which is which saves time. The welcome dialog asks for the most common parameters: mode, classes and export format. Per-label configuration lives in labels/_classes.json. General settings live in config.ini, and the README points to the interactive documentation for a description of all parameters. The z-Rotation Only Mode toggle for 9 DoF boxes can be reached from the menu, the settings, or config.ini, which means a setting changed in the UI has a file-level equivalent you can version or script.
What the README does not give is a worked example of config.ini contents. The parameter names are documented on the linked configuration page rather than in the repository README, so plan on reading that page rather than guessing keys.
Where labelCloud stops being the right tool
The limitations are mostly consequences of being a single-user desktop tool, and they should be weighed before adoption rather than discovered later.
No collaboration layer is documented. There is no mention of a label review queue, inter-annotator agreement, or locking a file while someone else edits it. On a dataset that needs two passes, coordination happens outside the tool.
Import is a closed list. The exporter side has a documented extension point in BaseLabelFormat; the importer side does not, at least not in the README. If your sensor writes something unusual, that is a source-level problem.
Segmentation is box-shaped. As described above, the Assign button labels every point inside the current box with the current class, and no refinement tool is documented. For classes that do not fill their bounding boxes, the resulting bin files will carry label noise that you cannot fix inside labelCloud.
The np.int8 label dtype is a hard ceiling on class count and a positional dependency on point ordering. Neither is a bug, but both constrain how the output can be post-processed.
Finally, the release cadence is worth noting without reading anything into it. The listed releases are v1.0.1 in February 2023, v1.1.0 in November 2023, and v1.1.1 in August 2024. The repository is not archived and the last push is later than the last release, so the project is not abandoned, but a user who needs a fix on a specific schedule should check the issue tracker themselves rather than assume one.
What it is not: a comparison with a full annotation platform
The natural alternative is a general annotation platform that includes 3D point cloud support alongside images and text, with user accounts, task assignment and a review workflow. The difference is not feature count. It is where the data lives and who controls the schema.
With labelCloud, the label schema is a JSON file in the repository (labels/_classes.json), the export format is a class you can subclass, and the whole thing runs from a Python process on your machine. Nothing leaves the workstation unless you move it. That is attractive when the point clouds are large, when the data is sensitive, or when the label format is unusual enough that a platform's fixed export would require a conversion script anyway.
A platform wins on the things labelCloud does not attempt: distributing work across annotators, tracking who labeled what, and reviewing before export. If your bottleneck is throughput across people rather than the format of the output, the platform is the correct choice and labelCloud is a detour. The honest framing is that these solve different problems, and picking labelCloud because it is lighter is only correct if the lighter shape actually matches how your labels get made.
Licence and the cost of staying current
labelCloud is GPL-3.0. That is a copyleft licence, and it matters most if you plan to modify labelCloud and distribute the result, or to link it into a product you ship. Using it internally to produce label files does not raise the same question as redistributing a modified binary. This is not legal advice; if your use involves shipping anything derived from the source, have someone qualified read the licence against your specific plan.
Maintenance cost is low by construction. There is no service to run and no database. Upgrades are pip install labelCloud or a git pull, and the risk surface is the config files: config.ini and labels/_classes.json are the two places where your local customizations live, and both are the kind of file that a careless pull can overwrite. Keeping them under version control outside the repository is the cheap precaution.
The exporter base class is the other long-term consideration. If you write a custom BaseLabelFormat subclass, it is your code against an interface that has changed across the v1.0 to v1.1 releases. Pin the version you build against and read the release notes before moving.
Editorial conclusion
Adopt labelCloud if you need to produce 3D box labels from point clouds on a single workstation and you want the label format to match an existing convention rather than a vendor's. Do not adopt it if you need multi-annotator review, a hosted labeling service, or a format that is not among the exporters listed in the README. Before committing, verify three things: that your point cloud format appears in the import table, that your target label format has an exporter (or that subclassing BaseLabelFormat is acceptable work), and that the z-Rotation Only Mode default matches whether you actually need 9 DoF boxes.
Community notes