Working with NDI Tracking Systems
The ndi_tracking module provides Python bindings for NDI (Northern Digital Inc.) tracking devices, enabling instrument tracking in custom
ImFusion applications.
NDI offers two fundamentally different tracking technologies:
Optical tracking (Polaris systems): An infrared camera detects reflective or active LED markers attached to instruments and computes their 6-DoF poses. Requires clear line-of-sight between the camera and the tracked tools.
Electromagnetic tracking (Aurora): A magnetic field generator creates a working volume in which small EM sensors embedded in instruments are tracked. Works through soft tissue without requiring line-of-sight, but is sensitive to nearby ferromagnetic objects.
Two stream classes are available, corresponding to different NDI hardware families:
Class |
Hardware |
Connection |
|---|---|---|
|
Polaris Vega, Polaris Lyra |
Ethernet (TCP/IP) |
|
Aurora |
USB / serial |
Note
Import the ndi_tracking module before using any of the classes below.
The imfusion.stream module is imported automatically as a dependency.
import imfusion
import ndi_tracking
Optical Tracking with Polaris Vega / Lyra
The NDIPolarisTrackingStream connects to a Polaris Vega or Lyra
system over Ethernet. Each tracked instrument must be described by a .rom file that
encodes the 3-D geometry of its reflective markers. ROM files can be obtained from NDI
for standard instruments or created with the NDI Cygna 6D software for custom tools.
Basic setup with two tools:
import imfusion
import ndi_tracking
stream = ndi_tracking.NDIPolarisTrackingStream()
stream.ip_address = "192.168.1.42" # IP of the Polaris system
stream.port = 8765 # default NDI port
stream.add_tracking_marker("C:/NDI/tools/pointer.rom", "Pointer")
stream.add_tracking_marker("C:/NDI/tools/reference.rom", "Reference Frame")
stream.open()
stream.start()
Use ip_address = "auto" when the Polaris system is on the same subnet and you
want automatic IP detection:
>>> stream = ndi_tracking.NDIPolarisTrackingStream()
>>> stream.ip_address = "auto"
>>> stream.add_tracking_marker("C:/NDI/tools/pointer.rom", "Pointer")
>>> stream.open()
>>> stream.start()
To record the tracking data, pass the stream into a
imfusion.stream.StreamRecorderAlgorithm:
import time
import imfusion
import ndi_tracking
stream = ndi_tracking.NDIPolarisTrackingStream()
stream.ip_address = "192.168.1.42"
stream.add_tracking_marker("C:/NDI/tools/pointer.rom", "Pointer")
stream.open()
stream.start()
recorder = imfusion.stream.StreamRecorderAlgorithm([stream])
recorder.start()
time.sleep(5) # record for 5 seconds
recorder.stop()
stream.stop()
stream.close()
tracking_sequences = recorder.output()
imfusion.save(tracking_sequences, "tracking.imf")
Electromagnetic Tracking with Aurora
The NDIAuroraTrackingStream connects to an NDI Aurora EM tracking
system via USB. Unlike the optical systems, a ROM file registration is typically not needed —
instruments are auto-detected when the stream is opened.
import imfusion
import ndi_tracking
stream = ndi_tracking.NDIAuroraTrackingStream()
stream.hardware_device = "auto"
stream.open()
stream.start()
# all connected EM sensors are available automatically
The measurement rate can be configured before opening the stream. List the available options and select by index:
stream = ndi_tracking.NDIAuroraTrackingStream()
stream.hardware_device = "auto"
options = stream.measurement_rate_options
print("Available rates:", options)
stream.measurement_rate = next(
i for i, r in enumerate(options) if r == "115200"
)
stream.open()
stream.start()
Custom ROM files for Aurora probes
Standard Aurora instruments are auto-detected on open(). For custom probes that ship
with a ROM file, call register_tool() before
opening the stream:
stream = ndi_tracking.NDIAuroraTrackingStream()
stream.hardware_device = "auto"
stream.register_tool("Custom Probe", "C:/NDI/tools/custom_probe.rom", 3) # the tool is plugged into port 3
stream.open()
stream.start()
Note
EM tracking accuracy degrades near ferromagnetic objects (steel tables, surgical tools). Always validate the tracking accuracy in the intended clinical environment.
Working with Tracking Data
Both stream classes derive from imfusion.stream.TrackingStream. Recorded
output is a list of imfusion.TrackingSequence objects, one per registered tool.
Each imfusion.TrackingSequence holds a time series of 4×4 transformation
matrices representing the tool poses in the tracker’s coordinate system.
import time
import imfusion
import ndi_tracking
# Set up whichever stream type matches your hardware
stream = ndi_tracking.NDIPolarisTrackingStream()
stream.ip_address = "192.168.1.42"
stream.add_tracking_marker("C:/NDI/tools/pointer.rom", "Pointer")
stream.add_tracking_marker("C:/NDI/tools/reference.rom", "Reference")
stream.open()
stream.start()
recorder = imfusion.stream.StreamRecorderAlgorithm([stream])
recorder.start()
time.sleep(3)
recorder.stop()
stream.stop()
stream.close()
sequences = recorder.output()
for seq in sequences:
print(f"Tool '{seq.tracker_id.name}': {seq.size} poses recorded")
# Save to disk for later processing
imfusion.save(sequences, "navigation_recording.imf")