Pupil Core camera synchronisationΒΆ

We used this protocol to investigate how well Pupil Capture synchronises the clocks of the Eye and World cameras on a Pupil Core headset. See here for a detailed explanation and analysis showing how this is dependant on operating system and camera settings.

[2]:
from time import sleep

from pyplr.stlab import SpectraTuneLab, pulse_protocol
from pyplr.pupil import PupilCore

# Set up pupil
p = PupilCore()

# Annotations / notifications can crash Capture if they are sent too
# close together so we will wait and send them at the end of the script
p.annotation_capture_plugin(should='stop')
sleep(.02)

# Setup stlab and make spectrum with near-IR
d = SpectraTuneLab(password='****************')
spec = [0, 0, 0, 0, 0, 0, 0, 4095, 0, 0]
pulse_protocol(spec, 1000, '1s_near_IR_pulse')
d.load_video_file('1s_near_IR_pulse.dsf')

# light_stamper params
threshold = 10
timeout = 6.

# Make annotations for each camera
world_annotation = p.new_annotation('LIGHT_ON_WORLD')
eye_0_annotation = p.new_annotation('LIGHT_ON_EYE_0')
eye_1_annotation = p.new_annotation('LIGHT_ON_EYE_1')

# Dict for the light_stamper timestamps
results = {'world': [],
           'eye_0': [],
           'eye_1': []}

# Start recording and wait a while
p.command('R pupil_core_camera_sync_tests')
sleep(5.)

# Begin testing protocol
for i in range(3):
    # Start light_stampers
    lst_world = p.light_stamper(
        world_annotation,
        threshold,
        timeout,
        topic='frame.world')
    lst_eye_0 = p.light_stamper(
        eye_0_annotation,
        threshold,
        timeout,
        topic='frame.eye.0')
    lst_eye_1 = p.light_stamper(
        eye_1_annotation,
        threshold,
        timeout,
        topic='frame.eye.1')

    # Wait 100 ms then flash light
    sleep(1.)
    d.play_video_file()
    sleep(timeout)

    # Add timestamps to results dictionary
    results['world'].append(lst_world.result())
    results['eye_0'].append(lst_eye_0.result())
    results['eye_1'].append(lst_eye_1.result())

# Start Annotation Capture plugin
p.annotation_capture_plugin(should='start')
sleep(.02)

# Send the annotations with 20 ms spacing
for k in results.keys():
    for ts in [val[1] for val in results[k]]:
        annotation = p.new_annotation('light_on_{}'.format(k))
        annotation['timestamp'] = ts
        p.send_annotation(annotation)
        sleep(0.02)

# Wait for 5 s and stop recording
sleep(5.)
p.command('r')

STLAB device setup complete...
"1s_near_IR_pulse.dsf" saved in the current working directory.
video file loaded...
> Waiting for a light to stamp...
> Waiting for a light to stamp...
> Waiting for a light to stamp...
playing video file...
> Light stamped on frame.eye.0 at 346194.799512
> Light stamped on frame.world at 346194.774064
> Light stamped on frame.eye.1 at 346194.805085
> Waiting for a light to stamp...
> Waiting for a light to stamp...
> Waiting for a light to stamp...
playing video file...
> Light stamped on frame.eye.0 at 346201.864576
> Light stamped on frame.eye.1 at 346201.870149
> Light stamped on frame.world at 346201.846864
> Waiting for a light to stamp...
> Waiting for a light to stamp...
> Waiting for a light to stamp...
playing video file...
> Light stamped on frame.world at 346208.919664
> Light stamped on frame.eye.0 at 346208.945881
> Light stamped on frame.eye.1 at 346208.951454
[2]:
'OK'