Dear Pupil Labs Team,
Iβd like to follow up once more to make sure I interpret this correctly, because my supervisor and I arrived at a different interpretation of your answer and this point is crucial for my thesis.
My supervisorβs interpretation is the following: since the IMU is rigidly mounted on the head, roll and pitch will reflect any motion the head undergoes, including motion induced by walking (i.e. even if the person intends to keep the head βstillβ, gait-related head movement would still be visible in roll/pitch, with no compensation applied).
However, my understanding from your previous message was that: if the IMU undergoes pure linear translation (e.g. walking forward) while its orientation relative to gravity remains constant, then roll and pitch do not change, because they are absolute, gravity-referenced orientation values.
To make this fully explicit, could you please clarify which of the two interpretations is correct? 1. Roll and pitch change whenever the head experiences motion during walking, because no compensation for gait-related head motion is applied or 2. Roll and pitch remain stable as long as the head orientation relative to gravity is constant, regardless of translational motion
I apologize for insisting, but this distinction is extremely important for how the IMU signals are interpreted and described in my thesis methodology.
Thank you very much for your patience and clarification.
Hello, @user-e61a82!
No problem at all. It is important to be accurate for your thesis, so let me clarify.
The short answer is that both you and your supervisor are correct, but you are looking at it from different angles.
You are right about the physics of the sensor. If the IMU moves forward in a straight line without tilting relative to gravity (pure translation), the roll and pitch values will not change. Pure linear motion does not affect these values. By definition it cannot because it doesn't induce tilt.
However, your supervisor is right about the practical reality of walking. During gait, it is very unlikely that a person can keep their head perfectly level. Humans naturally sway when walking. Since the IMU is rigidly mounted to the head, it will physically tilt along with the head. Therefore, you will likely see changes in pitch and roll.
In sum, you have to think of the IMU as an indepent sensor unit. It doesn't care what it's mounted to. We're not doing any kind of compensation for gait. The IMU is simply mounted to the head, that is actually rotating during the gait cycle, and thus records that orientation.
I hope this helps clear it up for your methodology section!
Moreover, I have one more question related to the world video frame rate that came up during data inspection, and I would appreciate your insight.
I analyzed the world camera timestamps for 82 Pupil Invisible recordings collected outdoors (real-world road environment, no controlled lighting). Across all recordings, the effective frame rate is extremely stable at ~20 fps: β’ mean β 19.97β20.00 fps β’ max = exactly 20 fps β’ std β 0 in many recordings
Lower values (e.g. 3β10 fps) only appear in the first or last second of a recording, likely due to partial seconds.
According to the documentation, a stable frame rate is expected under constant lighting conditions, while variable lighting may lead to frame rate adaptation. However, these recordings were collected outdoors with clearly varying illumination conditions, yet the frame rate remains locked at ~20 fps with almost no variation.
This raises two questions I would like to clarify: 1. Is the world camera frame rate for Pupil Invisible capped or intentionally fixed at ~20 fps, regardless of lighting conditions? 2. If the nominal specification is 30 fps, could you clarify why the exported world videos consistently appear at 20 fps instead?
Any explanation of the underlying behavior (e.g. sensor limits, exposure strategy, power constraints, or processing choices) would be very helpful for correctly documenting this in my thesis.
Once again, thanks a lot in advance for your help!
There are two exposure modes for the scene camera, 1. Auto-exposure, and 2. Manual exposure. If the framerate is consistent at 20 fps, it's likely that a manual exposure value was set by someone prior to recording (in the Companion app settings) Auto-exposure would have yielded 30fps in outdoor conditions in our experience.
Thanks a lot for the clarification β this makes it very clear.
The distinction between pure translation and gait-induced head motion is exactly what I needed for the methodology section. Also thanks for the explanation about the frame rate; Iβll check the Companion app settings regarding manual exposure.
Much appreciated!
Hi there, I am looking for the scene camera matrix and distortion coefficient to produce radius, elevation and azimuth from gaze x,y with my pupil invisible glasses. I could not find scene camera matrix and distortion coefficient from recording folder after updated with Pupil Player but I found this "glasses_serial_number":"vb23k" and "scene_camera_serial_number":"9xy3j" from info.invisible.json. Can you please give us scene camera matrix and distortion coefficient from this serial number? Please also guide me how I can get elevation and azimuth from gaze x and y from pupil invisible. Is it the same calculation as pupil neon?
Hi @user-b10192 , the camera calibration data is contained in the scene_camera.json file, or are you working with the Native Recording Data?
And, yes, the calculation is the same as with Neon. If you need more info, just let us know.
Hi @user-f43a29 , I could not find the scene_camera.json file. How can I get it. I recorded with pupil invisible phone and plug into laptop then I drag and drop that recording folder into Pupil Player. What step did I miss? Could you please guide me? Is this the rigth camera matrix and distortion coefficients for pupil invisible glasses ("glasses_serial_number":"vb23k" and "scene_camera_serial_number":"9xy3j")? "PI world v1": { "(1088, 1080)": { "dist_coefs": [ [ -0.12390715699556255, 0.09983010007937897, 0.0013846287331131738, -0.00036539454816030264, 0.020072404577046853, 0.2052173022520547, 0.009921380887245364, 0.06631870205961587, ] ], "camera_matrix": [ [766.2927454396544, 0.0, 543.6272327745995], [0.0, 766.3976103393867, 566.0580149497666], [0.0, 0.0, 1.0], ], "cam_type": "radial", } },
Hi @user-b10192 , I see.
The scene_camera.json file is produced by Pupil Cloud.
If you are using the Native Recording Data (i.e., the recording folder that you drag into Pupil Player), then the intrinsics are saved in binary files. Once you open the recording in Pupil Player, you should see three files, called eye0.intrinsics, eye1.intrinsics, and world.intrinsics, in the recording folder. These contain the matrix/distortion parameters for each of the cameras on your Pupil Invisible. Note that in the case of Pupil Invisible, average fallbacks are used in Pupil Player.
If you want the values for your particular Pupil Invisible device, then use the scene_camera.json file obtained by downloading a recording from Pupil Cloud.
In any event, the intrinsic values that you found in Pupil Player's source code are used used to make those offline *.intrinscis files, so if that is sufficient for you, then you can either copy-paste those values that you found, or you can use the binary files. To inspect the values in the binary files, you can load them into Python as follows:
import msgpack
with open("world.intrinsics", "rb") as fh:
camera_data = msgpack.unpack(fh)
print(camera_data[b"(1088, 1080)"][b"camera_matrix"])
print()
print(camera_data[b"(1088, 1080)"][b"dist_coefs"])
For this, you will need the msgpack library installed in a Python virtual environment:
pip install msgpack==0.5.6
Thanks. This helps a lot.