Examples

The EnsensoSDK includes all the examples described on this page in its installation directory, which you can list like this:

ls $ENSENSO_INSTALL/development/examples/Python

nx_save_images_verbose.py

The following code shows how the Python API is used to initialize the NxLib, open a camera with a given serial number, capture an image pair, rectify those images and then save both the raw and the rectified images as PNG files. This example is utterly verbose since it contains a lot of boilerplate code. The examples below show how this boilerplate code can be reduced to a minimum.

import argparse

import nxlib.api as api
from nxlib import NxLibCommand, NxLibException, NxLibItem
from nxlib.constants import *


def get_camera_node(serial):
    # Get the root of the tree.
    root = NxLibItem()
    # From here on we can use the [] operator to walk the tree.
    cameras = root[ITM_CAMERAS][ITM_BY_SERIAL_NO]
    for i in range(cameras.count()):
        found = cameras[i].name() == serial
        if found:
            return cameras[i]


parser = argparse.ArgumentParser()
parser.add_argument("serial", type=str,
                    help="the serial of the stereo camera to open")
args = parser.parse_args()

camera_serial = args.serial

try:
    # Wait for the cameras to be initialized
    api.initialize()

    # Open the camera with the given serial
    with NxLibCommand(CMD_OPEN) as cmd:
        cmd.parameters()[ITM_CAMERAS] = camera_serial
        cmd.execute()

    # Capture with the previously opened camera
    with NxLibCommand(CMD_CAPTURE) as cmd:
        cmd.parameters()[ITM_CAMERAS] = camera_serial
        cmd.execute()

    # Rectify the images
    with NxLibCommand(CMD_RECTIFY_IMAGES) as cmd:
        cmd.execute()

    # Get the NxLib node of the open camera
    camera = get_camera_node(camera_serial)

    # Save the raw and rectified images
    with NxLibCommand(CMD_SAVE_IMAGE) as cmd:
        if camera[ITM_TYPE].as_string() == VAL_STEREO:
            cmd.parameters()[ITM_NODE] = camera[ITM_IMAGES][ITM_RAW][ITM_LEFT].path
            cmd.parameters()[ITM_FILENAME] = "raw_left.png"
            cmd.execute()

            cmd.parameters()[ITM_NODE] = camera[ITM_IMAGES][ITM_RAW][ITM_RIGHT].path
            cmd.parameters()[ITM_FILENAME] = "raw_right.png"
            cmd.execute()

            cmd.parameters()[ITM_NODE] = camera[ITM_IMAGES][ITM_RECTIFIED][ITM_LEFT].path
            cmd.parameters()[ITM_FILENAME] = "rectified_left.png"
            cmd.execute()

            cmd.parameters()[ITM_NODE] = camera[ITM_IMAGES][ITM_RECTIFIED][ITM_RIGHT].path
            cmd.parameters()[ITM_FILENAME] = "rectified_right.png"
            cmd.execute()
        else:
            cmd.parameters()[ITM_NODE] = camera[ITM_IMAGES][ITM_RAW].path
            cmd.parameters()[ITM_FILENAME] = "raw.png"
            cmd.execute()

            cmd.parameters()[ITM_NODE] = camera[ITM_IMAGES][ITM_RECTIFIED].path
            cmd.parameters()[ITM_FILENAME] = "rectified.png"
            cmd.execute()

    # Close the open camera
    with NxLibCommand(CMD_CLOSE) as cmd:
        cmd.execute()

except NxLibException as e:
    print(f"An NxLib error occured: Error Text: {e.get_error_text()}")
except Exception:
    print("An NxLib unrelated error occured:\n")
    raise

nx_save_stereo_images.py

The above example can be simplified by using the provided context manager protocol implementing classes nxlib.context.NxLib and nxlib.context.StereoCamera.

import argparse

from nxlib.context import NxLib, StereoCamera
from nxlib.command import NxLibCommand
from nxlib.constants import *


parser = argparse.ArgumentParser()
parser.add_argument("serial", type=str,
                    help="the serial of the stereo camera to open")
args = parser.parse_args()


def save_image(filename, item):
    with NxLibCommand(CMD_SAVE_IMAGE) as cmd:
        cmd.parameters()[ITM_NODE] = item.path
        cmd.parameters()[ITM_FILENAME] = filename
        cmd.execute()


with NxLib(), StereoCamera(args.serial) as camera:
    camera.capture()
    camera.rectify()
    save_image("raw_left.png", camera[ITM_IMAGES][ITM_RAW][ITM_LEFT])
    save_image("raw_right.png", camera[ITM_IMAGES][ITM_RAW][ITM_RIGHT])
    save_image("rectified_left.png", camera[ITM_IMAGES][ITM_RECTIFIED][ITM_LEFT])
    save_image("rectified_right.png", camera[ITM_IMAGES][ITM_RECTIFIED][ITM_RIGHT])

nx_save_mono_images.py

This example shows - as the above one - how the image of a mono camera can be saved as a PNG file by using the provided context manager protocol implementing classes nxlib.context.NxLib and nxlib.context.MonoCamera.

import argparse

from nxlib.context import NxLib, MonoCamera
from nxlib.command import NxLibCommand
from nxlib.constants import *


parser = argparse.ArgumentParser()
parser.add_argument("serial", type=str,
                    help="the serial of the mono camera to open")
args = parser.parse_args()


def save_image(filename, item):
    with NxLibCommand(CMD_SAVE_IMAGE) as cmd:
        cmd.parameters()[ITM_NODE] = item.path
        cmd.parameters()[ITM_FILENAME] = filename
        cmd.execute()


with NxLib(), MonoCamera(args.serial) as camera:
    camera.capture()
    camera.rectify()
    save_image("raw.png", camera[ITM_IMAGES][ITM_RAW])
    save_image("rectified.png", camera[ITM_IMAGES][ITM_RECTIFIED])

nx_save_structured_light_images.py

This example is analogous to the nx_save_stereo_images.py example using the provided context manager protocol implementing classes nxlib.context.NxLib and nxlib.context.StructuredLightCamera.

import argparse

from nxlib.context import NxLib, StructuredLightCamera
from nxlib.command import NxLibCommand
from nxlib.constants import *


parser = argparse.ArgumentParser()
parser.add_argument("serial", type=str,
                    help="the serial of the structured light camera to open")
args = parser.parse_args()


def save_image(filename, item):
    with NxLibCommand(CMD_SAVE_IMAGE) as cmd:
        cmd.parameters()[ITM_NODE] = item.path
        cmd.parameters()[ITM_FILENAME] = filename
        cmd.execute()


with NxLib(), StructuredLightCamera(args.serial) as camera:
    camera.capture()
    camera.rectify()
    save_image("raw.png", camera[ITM_IMAGES][ITM_RAW])
    save_image("rectified.png", camera[ITM_IMAGES][ITM_RECTIFIED])

nx_version.py

This example show how to use the nxlib.item.NxLibItem class and its methods to access the NxTree.

from nxlib import NxLib
from nxlib import NxLibItem
from nxlib import NxLibError
from nxlib.constants import *

with NxLib():
    major = NxLibItem()[ITM_VERSION][ITM_NX_LIB][ITM_MAJOR]
    minor = NxLibItem()[ITM_VERSION][ITM_NX_LIB][ITM_MINOR]
    build = NxLibItem()[ITM_VERSION][ITM_NX_LIB][ITM_BUILD]
    try:
        version = major.as_string() + minor.as_string() + build.as_string()
    except NxLibError:
        # "The 'as_*()' methods cannot be used to convert an item's value."
        pass
    if (major.is_int() and minor.is_int() and build.is_int()):
        version = ".".join(str(node.as_int()) for node in [major, minor, build])
        if major >= 4 or (major == 3 and minor > 3):
            print("Ensenso SDK installation contains Python interface")
        print(f"NxLib Version {version}")
    else:
        print("Unexpected node format detected")

nx_list_cams.py

This example iterates over all cameras listed by the NxLib and prints their serial number, model and status.

from nxlib import NxLibItem
from nxlib.constants import *
from nxlib.context import NxLib


def check_true(item):
    return item.exists() and item.as_bool() is True


def check_false(item):
    return item.exists() and item.as_bool() is False


with NxLib():
    # Reference to the serials subnode of all cameras
    cameras = NxLibItem()[ITM_CAMERAS]

    # Print status information for each camera
    print("SerialNo", " " * 8, "Model", " " * 10, "Status")
    for i in range(cameras.count()):
        if not cameras[i][ITM_STATUS].exists():
            continue
        if check_false(cameras[i][ITM_STATUS][ITM_VALID_IP_ADDRESS]):
            status = "Invalid Ip"
        elif check_true(cameras[i][ITM_STATUS][ITM_OPEN]):
            status = "Open"
        elif check_false(cameras[i][ITM_STATUS][ITM_AVAILABLE]):
            status = "In Use"
        elif check_false(cameras[i][ITM_STATUS][ITM_VALID_CAMERA_FIRMWARE]):
            status = "Invalid Camera Firmware"
        elif check_false(cameras[i][ITM_STATUS][ITM_VALID_PROJECTOR_FIRMWARE]):
            status = "Invalid Projector Firmware"
        elif check_false(cameras[i][ITM_STATUS][ITM_CALIBRATED]):
            status = "Not Calibrated"
        else:
            status = "Available"
        serial = cameras[i].name()
        model = cameras[i][ITM_MODEL_NAME].as_string()
        print(f"{serial:<17} {model:<16} {status:<16}")

nx_simple.py

This simple example opens a stereo camera, executes the complete pipeline that is necessary to get the computed point map and then calculates the average of the z values.

import argparse
import numpy as np

from nxlib import NxLib, Camera
from nxlib.constants import *


def filter_nans(point_map):
    """ Filter NaN values. """
    return point_map[~np.isnan(point_map).any(axis=1)]


def reshape_point_map(point_map):
    """ Reshape the point map array from (m x n x 3) to ((m*n) x 3). """
    return point_map.reshape(
        (point_map.shape[0] * point_map.shape[1]), point_map.shape[2])


def compute_z_value_average(point_map):
    """ Reshape and filter the point map, then calculate z-value average. """
    point_map = reshape_point_map(point_map)
    point_map = filter_nans(point_map)

    if point_map.shape[0] == 0:
        return 0.0

    z_idx = 2
    z_count, z_sum = 0, 0.0
    for i in range(point_map.shape[0]):
        z_sum += point_map[i][z_idx]
        z_count += 1

    return z_sum / z_count


parser = argparse.ArgumentParser()
parser.add_argument("serial", type=str,
                    help="the serial of the stereo camera to open")
args = parser.parse_args()


with NxLib(), Camera.from_serial(args.serial,
                                 [VAL_STRUCTURED_LIGHT, VAL_STEREO]) as camera:
    camera.capture()
    camera.rectify()
    camera.compute_disparity_map()
    camera.compute_point_map()

    z_value_average = compute_z_value_average(camera.get_point_map())
    print(f"The average z value in the point map is {z_value_average:.1f}mm")

nx_watch_point_cloud.py

This example opens a stereo camera, executes the complete pipeline that is necessary to get the computed point map and then renders the point cloud with open3d. If you do not have open3d installed, follow the instructions given at the top of the example file.

# This example requires the open3d package to be installed.
# Install it with: python3 -m pip install open3d

import argparse

import numpy as np
import open3d

from nxlib import NxLib
from nxlib import Camera
from nxlib.constants import *


def filter_nans(point_map):
    """ Filter NaN values. """
    return point_map[~np.isnan(point_map).any(axis=1)]


def reshape_point_map(point_map):
    """ Reshape the point map array from (m x n x 3) to ((m*n) x 3). """
    return point_map.reshape(
        (point_map.shape[0] * point_map.shape[1]), point_map.shape[2])


def convert_to_open3d_point_cloud(point_map):
    """ Convert numpy array to Open3D format. """
    point_map = reshape_point_map(point_map)
    point_map = filter_nans(point_map)
    open3d_point_cloud = open3d.geometry.PointCloud()
    open3d_point_cloud.points = open3d.utility.Vector3dVector(point_map)
    return open3d_point_cloud


parser = argparse.ArgumentParser()
parser.add_argument("serial", type=str,
                    help="the serial of the depth camera to open")
args = parser.parse_args()


with NxLib(), Camera.from_serial(args.serial,
                                 [VAL_STRUCTURED_LIGHT, VAL_STEREO]) as camera:
    camera.capture()
    camera.compute_disparity_map()
    camera.compute_point_map()
    # Watch the captured point cloud with open3d
    point_cloud = convert_to_open3d_point_cloud(camera.get_point_map())
    open3d.visualization.draw_geometries([point_cloud])

nx_log.py

This examples illustrates the use of the classes nxlib.log.NxLog and nxlib.log.NxDebugBlock. It opens a log in line 21, which collects all debug output from the NxLib, and a debug block named TestBlock in line 27. After line 35, the NxLog’s scope ends, causing the log file to be written to file. In this example, no filename was given and hence the log file will be written to nxlog/temp-0001.nxlog (which is composed of the default output path and a serially numbered default filename). Since the NxLog was created with open_in_profiler=True, the written log file will automatically be opened with the NxProfiler executable. In the visual log we can now see our debug message and our TestBlock among all other NxLib logging.

 1import argparse
 2
 3from nxlib import NxLib
 4from nxlib import NxLog
 5from nxlib import NxDebugBlock
 6from nxlib import StereoCamera
 7from nxlib.constants import *
 8
 9
10parser = argparse.ArgumentParser()
11parser.add_argument("serial", type=str,
12                    help="the serial of the stereo camera to open")
13args = parser.parse_args()
14
15
16with NxLib(), StereoCamera(args.serial) as camera:
17
18    # If desired: set the global log level for all further logs.
19    # NxLog.set_log_level(NX_LOG_LEVEL_INFO)
20
21    with NxLog(level=NX_LOG_LEVEL_DEBUG, open_in_profiler=True):
22
23        # Capture with the previously opened camera
24        camera.capture()
25        NxLog.write_debug_message("Capture done")
26
27        with NxDebugBlock(name="TestBlock"):
28            # Rectify the images
29            camera.rectify()
30
31        # Compute the disparity map
32        camera.compute_disparity_map()
33
34        # Compute the point map from the disparity map
35        camera.compute_point_map()
36        point_map = camera.get_point_map()

nx_log_remote_lib.py

The following example shows how the NxLibRemote class can be used in combination with the NxLog class to periodically read out the debug buffer of a remote NxLib.

import argparse
import time

from nxlib import NxLibRemote
from nxlib import NxLog

parser = argparse.ArgumentParser()
parser.add_argument("hostname", type=str,
                    help="the hostname of the remote NxLib")
parser.add_argument("filename", type=str,
                    help="the filename the log is written to")
parser.add_argument("-p", "--port", type=int, default=24000, metavar="P",
                    help="the port of the remote NxLib (default 24000)")
args = parser.parse_args()


with NxLibRemote(args.hostname, args.port):
    with open(args.filename, "wb") as f:
        try:
            while True:
                bytes_ = NxLog.get_debug_buffer()
                print(f"Received {len(bytes_)} bytes")
                f.write(bytes_)
                time.sleep(1)
        except KeyboardInterrupt:
            print("\nKeyboardInterrupt")