lidR (version 2.2.5)

sensor_tracking: Reconstruct the trajectory of the LiDAR sensor using multiple returns

Description

Use multiple returns to estimate the positioning of the sensor by computing the intersection in space of the line passing through the first and last returns. To work, this function requires a dataset where the 'gpstime', 'ReturnNumber', 'NumberOfReturns' and 'PointSourceID' attributes are properly populated, otherwise the output may be incorrect or weird. For LAScatalog processing it is recommended to use large chunks and large buffers (e.g. a swath width). The point cloud must not be normalized.

Usage

sensor_tracking(
  las,
  interval = 0.5,
  pmin = 50,
  extra_check = TRUE,
  thin_pulse_with_time = 0.001
)

Arguments

las

An object of class LAS or LAScatalog.

interval

numeric. Interval used to bin the gps times and group the pulses to compute a position at a given timepoint t.

pmin

integer. Minimum number of pulses needed to estimate a sensor position. For a given interval, the sensor position is not computed if the number of pulses is lower than pmin.

extra_check

boolean. Datasets are rarely perfectly populated, leading to unexpected errors. Time-consuming checks of data integrity are performed. These checks can be skipped as they account for an important proportion of the computation time. See also section 'Tests of data integrity'.

thin_pulse_with_time

numeric. In practice, it is useless to compute the position using all multiple returns. It is more computationally demanding but not necessarily more accurate. This keeps only one pulse every x seconds. Set to 0 to use all multiple returns. Use 0 if the file has already been read with filter = "-thin_pulses_with_time 0.001".

Value

A SpatialPointsDataFrame with the Z elevation stored in the table of attributes. Information about the time interval and the number of pulses used to find the points is also in the table of attributes.

Test of data integrity

In theory, sensor tracking is a simple problem to solve as long as each pulse is properly identified from a well-populated dataset. In practice, many problems may arise from datasets that are populated incorrectly. Here is a list of problem that may happen. Those with a * denote problems already encountered and internally checked to remove weird points:

  • 'gpstime' does not record the time at which pulses were emitted and thus pulses are not identifiable

  • *A pulse (two or more points that share the same gpstime) is made of points from different flightlines (different PointSourceID). This is impossible and denotes an improperly populated PointSourceID attribute.

  • 'ReturnNumber' and 'NumberOfReturns' are wrongly populated with either some ReturnNumber > NumberOfReturn or several first returns by pulses

For a given time interval, when weird points are not filtered, the position is not computed for this interval.

Working with a <code>LAScatalog</code>

This section appears in each function that supports a LAScatalog as input.

In lidR when the input of a function is a LAScatalog the function uses the LAScatalog processing engine. The user can modify the engine options using the available options. A careful reading of the engine documentation is recommended before processing LAScatalogs. Each lidR function should come with a section that documents the supported engine options.

The LAScatalog engine supports .lax files that significantly improve the computation speed of spatial queries using a spatial index. Users should really take advantage a .lax files, but this is not mandatory.

Supported processing options

Supported processing options for a LAScatalog (in bold). For more details see the LAScatalog engine documentation:

  • chunk size: How much data is loaded at once.

  • chunk buffer*: Mandatory to get a continuous output without edge effects. The buffer is always removed once processed and will never be returned either in R or in files.

  • chunk alignment: Align the processed chunks.

  • progress: Displays a progression estimation.

  • output_files: Saving intermediate results is disabled in 'sensor_tracking' because the output must be post-processed as a whole.

  • laz_compression: write las or laz files

  • select: is not supported. It is set by default to "xyzrntp"

  • filter: Read only points of interest. By default it uses "-drop_single" and "-thin_pulses_with_time" to reduce the number of points loaded.

Details

When multiple returns from a single pulse are detected, the sensor computes their positions as being in the center of the footprint and thus all aligned. Because of that behavior, a line drawn between and beyond those returns must cross the sensor. Thus, several consecutive pulses emitted in a tight interval (e.g. 0.5 seconds) can be used to approximate an intersection point in the sky that corresponds to the sensor position given that the sensor carrier hasn't moved much during this interval. A weighted least squares method gives an approximation of the intersection by minimizing the squared sum of the distances between the intersection point and all the lines.

Examples

Run this code
# NOT RUN {
# A valid file properly populated
LASfile <- system.file("extdata", "Topography.laz", package="lidR")
las = readLAS(LASfile)
plot(las)

# pmin = 15 because it is an extremely tiny file
# strongly decimated to reduce its size. There are
# actually few multiple returns
flightlines <- sensor_tracking(las, pmin = 15)

plot(las@header)
plot(flightlines, add = TRUE)

x <- plot(las)
add_flightlines3d(x, flightlines, radius = 10)

# Load only the data actually useful
las <- readLAS(LASfile,
               select = "xyzrntp",
               filter = "-drop_single -thin_pulses_with_time 0.001")
flightlines <- sensor_tracking(las)

x <- plot(las)
add_flightlines3d(x, flightlines, radius = 10)

# }
# NOT RUN {
# With a LAScatalog "-drop_single" and "-thin_pulses_with_time"
# are used by default
ctg = readLAScatalog("folder/")
flightlines <- sensor_tracking(ctg)
plot(flightlines)
# }

Run the code above in your browser using DataLab