Recording

The Blickfeld Qb2 provides a recording service that allows users to create recordings directly in the WebGUI. However, in some situations the WebGUI may not be accessible, and a recording must be created programmatically.

Please follow the Python Client Library Guide to install the Python package first.

Creating a recording

With the Stream method of the Record service, it is possible to request metadata and point cloud files to create a recording. The following code snippet shows how the toolkit service is used to retrieve the recording data as a stream. It is then written to a zip archive in the directory where the code was run. The structure of the resulting recording is explained in the section Recording archive structure.

import pathlib
import zipfile
from datetime import datetime

import blickfeld_qb2


def stream_recording(zip_archive: zipfile.ZipFile) -> None:
    # Create token factory using an application key
    token_factory = blickfeld_qb2.TokenFactory(
        application_key_secret="application-key-for-qb2-xxxxxxxxx"
    )

    # Open a secure connection to Qb2
    with blickfeld_qb2.Channel("qb2-xxxxxxxxx", token=token_factory) as channel:
        # Use recording service
        recording_service = blickfeld_qb2.toolkit.services.Record(channel=channel)

        # Request a recording stream from Qb2
        for response in recording_service.stream(
            # The type of point cloud to record, e.g. the full frame or only the foreground
            point_cloud_type=blickfeld_qb2.percept_pipeline.data.PointCloudType.POINT_CLOUD_TYPE_FULL,
            # Option to disable the states stream in the recording to reduce data
            disable_states=False,
            # Option to disable streaming of .vtu and .pcd formats to reduce data
            disable_vtu_and_pcd=False
        ):
            # The recording service sets a flag if data is potentially lost
            if response.data_loss:
                print("Potential data loss e.g. due to low network bandwidth")

            # Create a new file inside the zip archive
            with zip_archive.open(response.file.path, mode="w") as zf:
                # Write the data to the file
                zf.write(response.file.binary)


# Set the name of the recording
recording_name = f"recording_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.zip"

# The recording will be saved under the recording name
output_zip = pathlib.Path(recording_name)

# Create a zipfile at the set path to store the data from the stream
with zipfile.ZipFile(output_zip, mode="w", compression=zipfile.ZIP_STORED) as zip_archive:
    # Start the recording stream
    print("Start recording ...")
    try:
        stream_recording(zip_archive)

    # Stop the recording by pressing Ctrl+C
    except KeyboardInterrupt:
        zip_size_mb = sum([zinfo.file_size for zinfo in zip_archive.filelist]) / 1_000_000
        print(f"Finished recording {recording_name} with size {round(zip_size_mb, ndigits=1)} MB.")

Recording archive structure

Recordings created by the recording service follow the structure below. Using the fields of the RecordStreamRequest, the amount of data in the recording can be reduced by leaving out the states as well as the .vtu and .pcd files. The request can also be used to request a specific PointCloudType. Regardless of the requested type, the recorded point cloud frames will always be saved in the raw/ directory.

|-📁 recording/		                      # Archive containing the recorded data
| |-📁 states/			                  # Output of the states stream
|   |-states_timestamp-1.json		      # States captured at timestamp 1
|   |-states_timestamp-2.json
|   |- ...
|
| |-📁 raw/			                      # Point clouds in Frame format
|   |-frame_timestamp-1.pb		          # Frame at timestamp 1
|   |-frame_timestamp-2.pb
|   |- ...
|
| |-📁 metadata/                          # Configurations saved as .json
|   |-toolkitRecordStreamRequest.json     # RecordStreamRequest that was sent to start the recording
|   |-systemScanPattern.json              # The ScanPattern of the Qb2
|   |-systemFirmware.json                 # The Firmware running on the Qb2
|   |-perceptPipelineReferenceFrame.json  # The background point cloud as a Frame
|   |-perceptPipelinePerception.json      # The Perception settings of the Qb2
|   |-perceptPipelineDataSource.json      # The configured DataSource
|   |-hardwareIdentification.json         # The product Identification
|   |-coreProcessingAcceleration.json     # The measured Acceleration
|
| |-frame_frame-id-1.vtu                  # Point cloud at frame-id-1 as .vtu (1)
| |-frame_frame-id-1.pcd                  # Point cloud at frame-id-1 as .pcd (2)
| |-frame_frame-id-2.vtu
| |-frame_frame-id-2.pcd
| |- ...
1 .vtu files are in Visualization Toolkit (VTK) Unstructured Grid format. For more information, see: https://docs.vtk.org/en/latest/vtk_file_formats/vtkxml_file_format.html#unstructuredgrid
2 .pcd files are in Point Cloud Data format. For more information, see: https://pcl.readthedocs.io/projects/tutorials/en/master/pcd_file_format.html#pcd-file-format