Skip to content

Python bindings ๐Ÿ Getting started

han16nah edited this page Mar 12, 2022 · 20 revisions

This page will give an introduction on using HELIOS++ python bindings with pyhelios. pyhelios allows to:

  • Access and modify simulation configurations
  • Launch one or multiple simulations from your python script
  • Read point measurements and process further in combination with other python modules

Importing pyhelios

The package pyhelios is contained in the distribution root folder. It consists of different python scripts and the python-helios bindings. These bindings are actually present in the run-folder as _pyhelios.pyd/[.so], but are imported when you import pyhelios. The python scripts contain functions to create and work with simulations (e.g., SimulationBuilder) and a util subpackage, where tools for scene generation and flight planning are found.

Before importing, make sure that the HELIOS++ root directory is either the current working folder or added to the PATH environment variable, e.g. using set PATH=%PATH%;C:\path\to\helios-plusplus-win (on Windows). Then you can run:

# PyHelios import
import pyhelios

Configure simulation context and build a simulation

# Sim context.
# Set logging.
pyhelios.loggingQuiet()
# pyhelios.loggingSilent()
# pyhelios.loggingDefault()
# pyhelios.loggingVerbose()
# pyhelios.loggingVerbose2()

# Set seed for default random number generator.
pyhelios.setDefaultRandomnessGeneratorSeed("123")

# print current helios version
print(pyhelios.getVersion())

To create a simulation object, we suggest to use the SimulationBuilder, as it includes setting default parameters and type checking:

# Build simulation parameters
simBuilder = pyhelios.SimulationBuilder(
        'data/surveys/demo/tls_arbaro_demo.xml',
        'assets/',
        'output/'
    )
simBuilder.setNumThreads(0)
simBuilder.setLasOutput(True)
simBuilder.setZipOutput(True)
simBuilder.setCallbackFrequency(0)  # Run without callback
simBuilder.setFinalOutput(True)     # Return output at join
simBuilder.setExportToFile(False)   # Disable export pointcloud to file
simBuilder.setRebuildScene(False)

There are two flags to configure how the output is received. To start surveys from a python script, but then perform further analysis separately on the resulting XYZ or LAS files, we might set simBuilder.setFinalOutput(False) and simBuilder.setExportToFile(True). To directly process the output in the python file but not additionally export it to output\Survey Playback, we might set simBuilder.setFinalOutput(True) and simBuilder.setExportToFile(False). By default, both flags are set to True.

You can also set the simulation frequency. With a frequency of 0 (default, and shown above), pausing and callbacks are not possible.

After setting all of the required options, create the SimulationBuild object:

sim = simBuilder.build()

Starting and pausing and simulation status

A built simulation is started with

sim.start()

With various functions, we can find out the simulation status.

  • sim.isStarted()
  • sim.isRunning()
  • sim.isPaused()
  • sim.isStopped()
  • sim.isFinished()

Example:

if sim.isStarted():
    print('Simulation has started!')

Output:

Simulation has started!

Simulations can also be paused, resumed and stopped:

  • sim.start()
  • sim.pause()
  • sim.resume()
  • sim.stop()

Example:

import time

sim.start()

if sim.isStarted():
    print('Simulation is started!')

time.sleep(1.)
sim.pause()

if sim.isPaused():
    print('Simulation is paused!')
    
if not sim.isRunning():
    print('Simulation is not running.')
    
time.sleep(5)
sim.resume()

if sim.isRunning():
    print('Simulation has resumed!')

while sim.isRunning():
    pass
# alternatively, we can block the thread until it is finished with sim.join()

if sim.isFinished():
    print('Simulation has finished.') 

Output:

Simulation is started!
Simulation is paused!
Simulation is not running.
Simulation has resumed!
Simulation has finished.

Output handling

The simulation output, i.e. measurement and trajectory points, can be accessed using sim.join(), if final output was enabled (simBuilder.setFinalOutput(True)).

# Create instance of PyHeliosOutputWrapper class using sim.join(). 
# Contains attributes 'measurements' and 'trajectories' which are Python wrappers of classes that contain the output vectors.
output = sim.join()

# Create instances of vector classes by accessing 'measurements' and 'trajectories' attributes of output wrapper.
measurements = output.measurements
trajectories = output.trajectories

# Each element of vectors contains a measurement point or point in trajectory respectively. Access through getPosition().
starting_point = trajectories[0].getPosition()
end_point = trajectories[len(trajectories) -1].getPosition()

# Access individual x, y and z vals.
print(f'Trajectory starting point : ({starting_point.x}, {starting_point.y}, {starting_point.z})')

print(f'Trajectory end point : ({end_point.x}, {end_point.y}, {end_point.z})')

The package pyhelios contains additional tools for output handling (pyhelios/output_handling.py). These allow to convert the trajectory and point outputs to lists or numpy arrays. If not executing python from the helios root directory, the path to the helios root directory has to be added to the python path, so the package is found.

import numpy

output = sim.join()
measurements_list, trajectory_list = pyhelios.outputToList(output)
measurements_array, trajectory_array = pyhelios.outputToNumpy(output)

Columns of the measurements list/array:

   0      1      2      3      4      5      6      7      8        9         10            11              12            13              14          15 
[pos.x, pos.y, pos.z, ori.x, ori.y, ori.z, dir.x, dir.y, dir.z, intensity, echoWidth, NumberOfReturns, ReturnNumber, FullwaveIndex, classification, gpsTime]

Columns of the trajectories list/array:

   0      1      2      3       4      5     6
[pos.x, pos.y, pos.z, gpsTime, roll, pitch, yaw]

Consequently, to obtain x, y and z coordinates of the measurement ouput, you can use:

coords = measurements_array[:, :3]

Hint: If the hitObjectId should be included in the measurements array and numerical scenepart IDs are used, line 37 in pyhelios\output_handling can be changed to:

int(meas.hitObjectId)

Next steps

To allow you to dive more into scene manipulation with pyhelios, we have compiled some information on a separate page.