Examples
These examples may help you get started with PyHeadTracker. You can find more here.
Supperware
This example demonstrates how to use the Supperware Head Tracker with PyHeadTracker and send the orientation data via OSC to the IEM SceneRotator.
import pyheadtracker as pht
osc_send = pht.out.IEMSceneRotator(ip="127.0.0.1", port=7000)
ht = pht.supperware.HeadTracker1(
device_name="Head Tracker 1",
device_name_output="Head Tracker 2",
refresh_rate=50,
compass_on=True,
orient_format="q",
)
ht.open(compass_force_calibration=False)
ht.zero()
while True:
try:
orientation = ht.read_orientation()
if isinstance(orientation, pht.Quaternion):
osc_send.send_orientation(orientation)
# Print the quaternion values for debugging
print(
f"WXYZ: {orientation[0]:7.2f} {orientation[1]:7.2f} {orientation[2]:7.2f} {orientation[3]:7.2f}",
end="\r",
)
except (EOFError, KeyboardInterrupt):
print("\nClosing connection.")
ht.close()
break
Camera-based tracking
This example demonstrates how to use the MediaPipe Face Landmarker for webcam-based head tracking with PyHeadTracker. The orientation data is sent via OSC to the IEM SceneRotator.
import pyheadtracker as pht
scenerotator_send = pht.out.IEMSceneRotator(ip="127.0.0.1", port=7000)
roomencoder_send = pht.out.IEMRoomEncoder(ip="127.0.0.1", port=7001, mode="listener")
ht = pht.cam.MPFaceLandmarker(0, orient_format="ypr")
ht.open()
ht.zero()
while True:
try:
pose = ht.read_pose()
if pose is not None:
orientation = pose["orientation"]
position = pose["position"]
else:
continue
if isinstance(orientation, pht.YPR):
scenerotator_send.send_orientation(orientation)
if isinstance(position, pht.Position):
roomencoder_send.send_position(position)
if isinstance(orientation, pht.YPR) and isinstance(position, pht.Position):
print(
f"Yaw: {orientation.yaw:.2f}, Pitch: {orientation.pitch:.2f}, Roll: {orientation.roll:.2f} | X: {position.x:.2f}, Y: {position.y:.2f}, Z: {position.z:.2f}",
end="\r",
)
except (EOFError, KeyboardInterrupt):
print("\nClosing connection.")
ht.close()
break
openXR
In this example, we use the openXR bindings to retrieve head tracking data from a head mounted display, while rendering a dummy OpenGL scene. Orientation data is sent via OSC to the IEM SceneRotator and position data to the IEM RoomEncoder.
import pyheadtracker as pht
from OpenGL import GL
import xr
from xr.utils.gl import ContextObject
from xr.utils.gl.glfw_util import GLFWOffscreenContextProvider
scenerotator_send = pht.out.IEMSceneRotator(ip="127.0.0.1", port=7000)
roomencoder_send = pht.out.IEMRoomEncoder(ip="127.0.0.1", port=7001, mode="listener")
with ContextObject(
instance_create_info=xr.InstanceCreateInfo(
enabled_extension_names=[
# A graphics extension is mandatory (without a headless extension)
xr.KHR_OPENGL_ENABLE_EXTENSION_NAME,
],
),
context_provider=GLFWOffscreenContextProvider(),
) as context:
# Create a head tracker using OpenXR
ht = pht.hmd.openXR(context)
eye_colors = [
(0, 1, 0, 1), # Left eye green
(0, 0, 1, 1), # Right eye blue
(1, 0, 0, 1), # Third eye blind
]
run_idx = 0
try:
for frame_index, frame_state in enumerate(context.frame_loop()):
for view_index, view in enumerate(context.view_loop(frame_state)):
run_idx += 1
if run_idx == 20:
ht.zero()
GL.glClearColor(*eye_colors[view_index])
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
orientation = ht.read_orientation(frame_state)
position = ht.read_position(frame_state)
if orientation is not None:
scenerotator_send.send_orientation(orientation)
orientation_ypr = pht.utils.quat2ypr(orientation).to_degrees()
print(
f"Yaw: {orientation_ypr[0]:7.2f} {orientation_ypr[1]:7.2f} {orientation_ypr[2]:7.2f}",
end="\r",
)
if position is not None:
roomencoder_send.send_position(position)
# print(
# f"XYZ: {position.x:7.2f} {position.y:7.2f} {position.z:7.2f}",
# end="\r",
# )
except (EOFError, KeyboardInterrupt):
print("\nClosing connection.")