On this webpage we share and make publicly available both real and simulated 3D range data sets from the Institute of Automatic Control Engineering. To make storage and processing efficient, our data sets are provided in a binary format. Files have the extension *.pc (point cloud) and may contain an arbitrary number of frames, each of whichs contains an ASCII-identifier, a time stamp, a view point and the 3D point coordinates for one scanline.
To access the data, you have two options:
- If you simply want to view the data sets, you can download the (Windows) binary of our 3D Viewer. Due to the dependencies and required clean-up work we currently don't offer a source package for Linux, sorry :(.
-
If you want to use the data you will most likely want to convert it to a
different format suitable for your algorithms. To this end we provide the
following
Matlab script
to read the files. Save it in the same folder as the downloaded data sets, then type "help loadpcfile"
in Matlab to learn how to use it.
Note:It is not recommended to visualize point clouds in Matlab, as the 3D view will slow to a crawl when drawing more than a couple thousand line/point handles.
| Name | # Points | # Scanlines | Size | Preview |
|
Seat & Armchair Recorded with a Hokuyo UTM-30LX using only the front 180° Frequency: 40Hz Field of view: 180° Angular resolution: 0.25° 720 points/scanline |
![]() |
|||
| seat_armchair_horizontal | 297,360 | 413 | 6,991kB | ![]() |
| seat_armchair_vertical | 297,360 | 413 | 6,991kB | ![]() |
| seat_armchair_rotational | 110,880 | 154 | 2,608kB | ![]() |
|
Seat, Armchair, Table Recorded with a Hokuyo UTM-30LX using only the front 180° Frequency: 40Hz Field of view: 180° Angular resolution: 0.25° 720 points/scanline |
![]() |
|||
| seat_armchair_table_horizontal | 296,640 | 412 | 6,975kB | ![]() |
| seat_armchair_table_vertical | 297,360 | 413 | 6,991kB | ![]() |
| seat_armchair_rotational | 158,400 | 220 | 3,712kB | ![]() |
|
Two Chairs Recorded with a Hokuyo UTM-30LX using only the front 180° Frequency: 40Hz Field of view: 180° Angular resolution: 0.25° 720 points/scanline |
![]() |
|||
| two_chairs_horizontal | 198,720 | 276 | 4,671kB | ![]() |
| two_chairs_vertical | 295,920 | 411 | 6,959kB | ![]() |
| two_chairs_rotational | 177,840 | 247 | 4,176kB | ![]() |
The software framework that we currently use for simulation and segmentation of 3D range data has many dependencies and is not in any way cleaned up to allow for a public release. However, to facilitate a comparison of performance, we here provide the code which is at the core of our segmentation algorithm. Although it has undergone (and is still undergoing minor) modifications, the core clustering loop is that used and mentioned in several publications. In an implementation with linked lists, we have found this routine to perform significantly faster than region growing with seed points.
Note that the below snippets only provide relevant excerpts of the full classes and routines. In our code, the data structures make use of Qt containers, however, they can just as well be implemented with equivalent STL containers.
Using a point data structure like
struct SmartPoint { //! The point Point3F p; //! The normal Point3F n; //! The average Euclidean distance to the neighbors double ad; //! User pointer void *up; };
and a linked list point cloud class such as
//! Computes the normal vector of each point from its \a k nearest neighbors. void computeNormalVectors(int k=20); //! Segments the points by grouping all points with at least \a l neighbors within distance \a r and normal vector angle difference of \a a degrees. Removes clusters with less than \a nMin points. //! Appends smart point cloud \a other to this one. SmartPointCloud& operator<<(const SmartPointCloud &other); }
the clustering routine can be summarized as follows:
QList<SmartPointCloud*> SmartPointCloud::segmentByNormalVectors(double aMax, double rMax, int nMin) { if (aMax<=0) qDebug("[SmartPointCloud] Segmenting smart point cloud by normal vectors..."); time.start(); //Create a kd-tree if necessary, allocate space, prepare parameters if (!kdTree) kdTree = createKdTreeFromPoints(); ANNpointArray points = kdTree->thePoints(); const int k = MIN(50,count()-1); ANNidxArray indices = new ANNidx[k]; ANNdistArray distances = new ANNdist[k]; double aThresh = cos(aMax/180.0*M_PI); //Make sure normal vectors have been estimated if (!normalVectorsComputed) computeNormalVectors(k); //Create a temporary array of indices and clean the user pointers SmartPoint **pArray = new SmartPoint*[count()]; int i=0; for (iterator p=begin(); p!=end(); p++) { pArray[i] = (*p); pArray[i]->up = NULL; i++; } int id=0; for (iterator p=begin(); p!=end(); p++) { //Current point SmartPoint *cp = (*p); //Get the nearest neighbors double r = MIN(rMax,cp->ad); kdTree->annkFRSearch(points[id],r*r,k,indices,distances); //Now cluster for (int j=0; j<k; j++) { if (indices[j] == ANN_NULL_IDX) break; if (fabs(cp->n.dot(pArray[indices[j]]->n)) < aThresh) continue; //Neighbor point SmartPoint *np = pArray[indices[j]]; if (cp->up) { if (np->up) { //If points belong to the same cluster continue if (cp->up == np->up) continue; //Else merge the clusters (append the smaller to the larger) bool g = ((SmartPointCloud*)cp->up)->count() > ((SmartPointCloud*)np->up)->count(); SmartPointCloud *pc1 = g ? (SmartPointCloud*)cp->up : (SmartPointCloud*)np->up; SmartPointCloud *pc2 = g ? (SmartPointCloud*)np->up : (SmartPointCloud*)cp->up; for (iterator p=pc2->begin(); p!=pc2->end(); p++) (*p)->up = pc1; (*pc1) << (*pc2); delete pc2; } else { //Neighbor point doesn't have a cluster, add it to this one np->up = cp->up; ((SmartPointCloud*)cp->up)->append(np); } } else if (np->up) { //Add this point to neighbor cluster cp->up = np->up; ((SmartPointCloud*)np->up)->append(cp); } else { //Both points don't have a cluster -> Create a new one SmartPointCloud *nc = new SmartPointCloud; cp->up = (void*)nc; nc->append(cp); np->up = (void*)nc; nc->append(np); } } id++; } //Gather the clusters and delete the ones with less than nMin points QList<SmartPointCloud*> clusters; for (iterator p=begin(); p!=end(); p++) { SmartPointCloud *cluster = (SmartPointCloud*)(*p)->up; if (!cluster) continue; if (clusters.contains(cluster)) { p = --erase(p); continue; } if (cluster->count() < nMin) { for (iterator cp=cluster->begin(); cp!=cluster->end(); cp++) (*cp)->up = NULL; delete cluster; } else { p = --erase(p); clusters.append(cluster); } } //The point array and kd-tree are no longer valid for this point cloud annDeallocPts(points); delete kdTree; kdTree = NULL; //Clean up and return delete indices; delete distances; delete inRange; delete pArray; qDebug("[SmartPointCloud] Done (%d ms). %d cluster(s).",time.elapsed(),clusters.count()); return clusters; }











