Example usage#

To run the examples, install the package using the examples extras requirement:

pip install -e pupil-core-network-client[examples]

Connect, and start and stop a recording#

 1import argparse
 2import time
 3
 4import pupil_labs.pupil_core_network_client as pcnc
 5
 6
 7def main(address: str, port: int):
 8    device = pcnc.Device(address, port)
 9
10    print("Version:", device.request_version())
11    print("Start recording:", device.request_recording_start())
12    print("Waiting 5 seconds..")
13    time.sleep(5.0)
14    print("Stop recording:", device.request_recording_stop())
15
16
17if __name__ == "__main__":
18    parser = argparse.ArgumentParser()
19    parser.add_argument("-a", "--address", type=str, default="127.0.0.1")
20    parser.add_argument("-p", "--port", type=int, default=50020)
21    args = parser.parse_args()
22
23    main(args.address, args.port)

Start the Annotation Plugin and send custom annotions#

 1import argparse
 2import time
 3
 4import pupil_labs.pupil_core_network_client as pcnc
 5
 6
 7def main(address: str, port: int):
 8    device = pcnc.Device(address, port)
 9
10    print(
11        "Requesting annotation plugin start...",
12        device.request_plugin_start("Annotation_Capture"),
13    )
14    print("Wait a second for the request to be processed...")
15    time.sleep(1.0)
16
17    print(
18        "Sending annotation with automatic timestamp",
19        device.send_annotation(label="automatic timestamp"),
20    )
21
22    print(
23        "Sending annotation with custom timestamp",
24        # Timestamps should be in Pupil time. By subtracting 5 seconds, the annotation
25        # will be associated with a point in time 5 seconds ago.
26        device.send_annotation(
27            label="custom timestamp", timestamp=device.current_pupil_time() - 5.0
28        ),
29    )
30
31    print(
32        "Sending annotation with custom fields",
33        # Custom fields can be passed as keyword arguments and will be saved to their
34        # dedicated column during the Pupil Player export
35        device.send_annotation(
36            label="custom fields", trial=5, subject="me", condition="eye tracking"
37        ),
38    )
39
40
41if __name__ == "__main__":
42    parser = argparse.ArgumentParser()
43    parser.add_argument("-a", "--address", type=str, default="127.0.0.1")
44    parser.add_argument("-p", "--port", type=int, default=50020)
45    args = parser.parse_args()
46
47    main(args.address, args.port)

Stream Video From Pupil Capture#

 1import argparse
 2import contextlib
 3import logging
 4import time
 5
 6import pupil_labs.pupil_core_network_client as pcnc
 7
 8
 9def main(address: str, port: int, max_frame_rate_hz: int):
10    device = pcnc.Device(address, port)
11    device.send_notification(
12        {"subject": "frame_publishing.set_format", "format": "bgr"}
13    )
14
15    with contextlib.suppress(KeyboardInterrupt):
16        with device.subscribe_in_background("frame.world", buffer_size=1) as sub:
17            while True:
18                message = sub.recv_new_message()
19                print(
20                    f"[{message.payload['timestamp']}] {message.payload['topic']} "
21                    f"{message.payload['index']}"
22                )
23                time.sleep(1 / max_frame_rate_hz)
24
25
26if __name__ == "__main__":
27    parser = argparse.ArgumentParser()
28    parser.add_argument("-a", "--address", type=str, default="127.0.0.1")
29    parser.add_argument("-p", "--port", type=int, default=50020)
30    parser.add_argument("-fps", "--max-frame-rate", type=int, default=10)
31    parser.add_argument("--debug", action="store_true")
32    args = parser.parse_args()
33    logging.basicConfig(level=logging.DEBUG if args.debug else logging.WARNING)
34
35    main(args.address, args.port, args.max_frame_rate)

Stream Video to Pupil Capture#

This example shows how start world and eye plugins and streaming BGR data to Pupil Capture’s HMD Streaming backend.

 1import argparse
 2import contextlib
 3import time
 4
 5import numpy as np
 6
 7import pupil_labs.pupil_core_network_client as pcnc
 8
 9current_image = np.zeros((400, 600, 3), dtype=np.uint8)
10
11
12def main(address: str, port: int, frame_rate_hz: int):
13    device = pcnc.Device(address, port)
14
15    source_class_name = "HMD_Streaming_Source"
16    frame_topic = "hmd_streaming.custom"
17    device.request_plugin_start(source_class_name, args={"topics": (frame_topic,)})
18    for eye_id in range(2):
19        device.request_plugin_start_eye_process(
20            eye_id, source_class_name, args={"topics": (frame_topic,)}
21        )
22
23    with contextlib.suppress(KeyboardInterrupt):
24        # Enable sending messages directly to the IPC backbone instead of having
25        # Pupil Remote forward every message one by one and waiting for a response each
26        # time. This allows sending messages with a much higher rate.
27        with device.high_frequency_message_sending():
28            increasing_index = 0
29            while True:
30                send_image(
31                    device,
32                    gray_image(increasing_index),
33                    frame_topic,
34                    increasing_index,
35                    timestamp=device.current_pupil_time(),
36                )
37                increasing_index += 1
38                time.sleep(1 / frame_rate_hz)
39
40
41def send_image(device: pcnc.Device, image, topic: str, index: int, timestamp: float):
42    height, width, depth = image.shape
43    device.send_message(
44        {
45            "format": "bgr",
46            "projection_matrix": [  # dummy pin-hole camera intrinsics
47                [1000, 0.0, width / 2.0],
48                [0.0, 1000, height / 2.0],
49                [0.0, 0.0, 1.0],
50            ],
51            "topic": topic,
52            "width": width,
53            "height": height,
54            "index": index,
55            "timestamp": timestamp,
56            "__raw_data__": [image],
57        }
58    )
59
60
61def gray_image(color_seed: int):
62    """Return an image with a gray value between 85 and 170"""
63    return current_image + (color_seed % 85) + 85
64
65
66if __name__ == "__main__":
67    parser = argparse.ArgumentParser()
68    parser.add_argument("-a", "--address", type=str, default="127.0.0.1")
69    parser.add_argument("-p", "--port", type=int, default=50020)
70    parser.add_argument("-fps", "--frame-rate", type=int, default=60)
71    args = parser.parse_args()
72
73    main(args.address, args.port, args.frame_rate)