The LidarScan Representation

The LidarScan class is explained in depth in the Lidar Scan API, which we recommend reading.

We provide example code to aid in understanding.

To run the sample code which queries fields from a scan, use the pcap.pcap_query_scan() example:

$ python3 -m ouster.sdk.examples.pcap $SAMPLE_DATA_PCAP_PATH $SAMPLE_DATA_JSON_PATH query-scan

You can run the above on pcaps containing packets of any type of UDPProfileLidar.

You might notice that on a pcap containing dual returns data, you should note that your dtypes will not be consistently uint32_t, as you can tell from the result of running query-scan on dual returns data:

Available fields and corresponding dtype in LidarScan
RANGE           uint32
RANGE2          uint32
SIGNAL          uint16
SIGNAL2         uint16
REFLECTIVITY    uint8
REFLECTIVITY2   uint8
NEAR_IR         uint16

Staggered vs Destaggered 2D Representations

To generate staggered and destaggered images yourself, you can try the following sample code:

import matplotlib.pyplot as plt
from more_itertools import nth

# ... `metadata` and `source` variables created as in the previous examples

scans = client.Scans(source)

# iterate `scans` and get the 84th LidarScan (it can be different with your data)
scan = nth(scans, 84)
ranges = scan.field(client.ChanField.RANGE)

# destagger ranges, notice `metadata` use, that is needed to get
# sensor intrinsics and correctly data transforms
ranges_destaggered = client.destagger(source.metadata, ranges)

plt.imshow(ranges_destaggered, cmap='gray', resample=False)

Projecting into Cartesian Coordinates

Let’s plot some points!

If you have a configured sensor, you can plot some points in XYZ using the client.plot_xyz_points() example:

$ python3 -m ouster.sdk.examples.client $SENSOR_HOSTNAME plot-xyz-points

That should open a 3D plot of a single scan of your location taken just now by your sensor. You should be able to recognize the contours of the scene around you.

If you don’t have a sensor, you can run the same code with our pcap.pcap_display_xyz_points() pcap example:

$ python3 -m ouster.sdk.examples.pcap $SAMPLE_DATA_PCAP_PATH $SAMPLE_DATA_JSON_PATH plot-xyz-points --scan-num 84

For visualizers which will stream consecutive frames from sensors or pcaps, check out our utilities in Visualizations in 3D.

Working with 2D and 3D Representations Simultaneously

The direct correlation between 2D and 3D representations in an Ouster sensor provides a powerful framework for working with the data. As an easy example, you might decide you want to look at only the 3D points within a certain range and from certain azimuth angles.

 1# obtain destaggered range
 2range_destaggered = client.destagger(metadata,
 3                                     scan.field(client.ChanField.RANGE))
 4
 5# obtain destaggered xyz representation
 6xyzlut = client.XYZLut(metadata)
 7xyz_destaggered = client.destagger(metadata, xyzlut(scan))
 8
 9# select only points with more than min range using the range data
10xyz_filtered = xyz_destaggered * (range_destaggered[:, :, np.newaxis] >
11                                  (range_min * 1000))
12
13# get first 3/4 of scan
14to_col = math.floor(metadata.mode.cols * 3 / 4)
15xyz_filtered = xyz_filtered[:, 0:to_col, :]

Since we’d like to filter on azimuth angles, first we first destagger both the 2D and 3D points, so that our columns in the HxW representation correspond to azimuth angle, not timestamp. (See Staggered vs Destaggered 2D Representations for an explanation on destaggering.)

Then we filter the 3D points xyz_destaggered by comparing the range measurement to range_min, which we can do because there is a 1:1 correspondence between the columns and rows of the destaggered representations of xyz_destaggered and range_destaggered. (Similarly, there would be a 1:1 correspondence between the staggered representations xyz and range, where the columns correspond with timestamp).

Finally, we select only the azimuth columns we’re interested in. In this case, we’ve arbitrarily chosen the first 270 degrees of rotation.

If you have a configured sensor, you can run this code with an example:

$ python3 -m ouster.sdk.examples.client $SENSOR_HOSTNAME filter-3d-by-range-and-azimuth