Home Forums Software Development Getting the Pupillary Distance

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #11839
    Chaim Dryzun
    Participant

    Hi,

    I am using the Tobii Eye Tracker 4C for gaze detection.
    I want to get the user’s Pupillary Distance – even the one in the calibration.
    How can I extract this data?

    thanks,
    Chaim

    #11846
    Grant [Tobii]
    Keymaster

    Hi @chaimdryzun1980 and thanks for your query. I am afraid the pupillary distance is not a metric that is directly exported either in the Tobii Core Software or the accompanying SDK’s.

    That being said, if you are a capable programmer, then I would recommend to take a look at the Tobii Stream Engine API which can provide you the x,y,z co-ordinates for each eye being tracked and from there you should be able to calculate the approximate distance between the centre of both pupils.
    You can download the stream engine API @ https://developer.tobii.com/consumer-eye-trackers/stream-engine/

    If this calculation is a one-off for your own interest then this should be sufficient, however if you are intending on developing an application that uses this metrics for analysis, you will be required to purchase an analytical use licence from Tobii. Further details about this you can read @ https://analyticaluse.tobii.com/

    Please do let us know if we can provide any further information. Best Wishes.

    #11848
    Chaim Dryzun
    Participant

    Hi,

    Thanks, for the quick reply.

    I will have a look at the Tobii Stream Engine API to understand how approximate the calculated DP is.

    For now, I am just doing a small research on different method for extracting the DP (using a ruler, image processing, depth camera and more). I just want to understand the accuracy, the precision and the comfort of use.If I will build an application, I will defiantly purchase the analytical use licence.

    Thanks,
    Chaim

    #11849
    Chaim Dryzun
    Participant

    Hi,

    I downloaded the Tobbi Stream Engine API and wrote a small C++ code.
    I succeeded getting the normalized eye position (tobii_eye_position_normalized_t) and the track box dimensions (tobii_track_box_t).
    I am trying to un-normalize the eye position and calculate the PD (pupillary distance).
    I get a number which seems in the right order, but it is very sensitive to the distance from the Tobii eye tracker (It becomes larger as I get closer to the eye tracker). I guess I need to perform some more distance normalization.

    Can you please help me understand which part am I missing?

    Here is my C++ code:

    #include <tobii/tobii.h>
    #include <tobii/tobii_streams.h>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <windows.h>
    #include <assert.h>

    tobii_track_box_t track_box;

    void eye_position_callback(tobii_eye_position_normalized_t const* eye_pos, void* user_data)
    {
    if ((eye_pos->left_validity == TOBII_VALIDITY_VALID) && (eye_pos->right_validity == TOBII_VALIDITY_VALID))
    {
    double N_X_L, N_Y_L, N_Z_L, N_X_R, N_Y_R, N_Z_R, U_X_L, U_Y_L, U_Z_L, U_X_R, U_Y_R, U_Z_R;
    N_X_L = eye_pos->left_xyz[0];
    N_Y_L = eye_pos->left_xyz[1];
    N_Z_L = eye_pos->left_xyz[2];

    N_X_R = eye_pos->right_xyz[0];
    N_Y_R = eye_pos->right_xyz[1];
    N_Z_R = eye_pos->right_xyz[2];

    U_X_L = ((track_box.back_lower_left_xyz[0] – track_box.front_upper_right_xyz[0]) * N_X_L);
    U_Y_L = ((track_box.back_lower_left_xyz[1] – track_box.front_upper_right_xyz[1]) * N_Y_L);
    U_Z_L = ((track_box.back_upper_right_xyz[2] – track_box.front_lower_left_xyz[2]) * N_Z_L);

    U_X_R = ((track_box.back_lower_left_xyz[0] – track_box.front_upper_right_xyz[0]) * N_X_R);
    U_Y_R = ((track_box.back_lower_left_xyz[1] – track_box.front_upper_right_xyz[1]) * N_Y_R);
    U_Z_R = ((track_box.back_lower_left_xyz[2] – track_box.front_upper_right_xyz[2]) * N_Z_R);

    double PD = sqrt(pow(U_X_R – U_X_L, 2.0) + pow(U_Y_R – U_Y_L, 2.0) + pow(U_Z_R – U_Z_L, 2.0));

    printf(“PD : %f\r”, PD);
    }
    }

    static void url_receiver(char const* url, void* user_data)
    {
    char* buffer = (char*)user_data;
    if (*buffer != ‘\0’) return; // only keep first value

    if (strlen(url) < 256)
    strcpy(buffer, url);
    }

    int main()
    {
    tobii_api_t* api;
    tobii_error_t error = tobii_api_create(&api, NULL, NULL);
    assert(error == TOBII_ERROR_NO_ERROR);

    char url[256] = { 0 };
    error = tobii_enumerate_local_device_urls(api, url_receiver, url);
    assert(error == TOBII_ERROR_NO_ERROR && *url != ‘\0’);

    tobii_device_t* device;
    error = tobii_device_create(api, url, &device);
    assert(error == TOBII_ERROR_NO_ERROR);

    error = tobii_eye_position_normalized_subscribe(device, eye_position_callback, 0);
    assert(error == TOBII_ERROR_NO_ERROR);

    error = tobii_get_track_box(device, &track_box);
    assert(error == TOBII_ERROR_NO_ERROR);

    // print just a couple of values of the track box data
    printf(“Front upper left is (%f, %f, %f)\n”,
    track_box.front_upper_left_xyz[0],
    track_box.front_upper_left_xyz[1],
    track_box.front_upper_left_xyz[2]);
    printf(“Front upper right is (%f, %f, %f)\n”,
    track_box.front_upper_right_xyz[0],
    track_box.front_upper_right_xyz[1],
    track_box.front_upper_right_xyz[2]);
    printf(“Front lower left is (%f, %f, %f)\n”,
    track_box.front_lower_left_xyz[0],
    track_box.front_lower_left_xyz[1],
    track_box.front_lower_left_xyz[2]);
    printf(“Front lower right is (%f, %f, %f)\n”,
    track_box.front_lower_right_xyz[0],
    track_box.front_lower_right_xyz[1],
    track_box.front_lower_right_xyz[2]);

    printf(“Back upper left is (%f, %f, %f)\n”,
    track_box.back_upper_left_xyz[0],
    track_box.back_upper_left_xyz[1],
    track_box.back_upper_left_xyz[2]);
    printf(“Back upper right is (%f, %f, %f)\n”,
    track_box.back_upper_right_xyz[0],
    track_box.back_upper_right_xyz[1],
    track_box.back_upper_right_xyz[2]);
    printf(“Back lower left is (%f, %f, %f)\n”,
    track_box.back_lower_left_xyz[0],
    track_box.back_lower_left_xyz[1],
    track_box.back_lower_left_xyz[2]);
    printf(“Back lower right is (%f, %f, %f)\n”,
    track_box.back_lower_right_xyz[0],
    track_box.back_lower_right_xyz[1],
    track_box.back_lower_right_xyz[2]);

    printf(“\n”);

    for (;;)
    {
    error = tobii_wait_for_callbacks(NULL, 1, &device);
    assert(error == TOBII_ERROR_NO_ERROR || error == TOBII_ERROR_TIMED_OUT);

    error = tobii_device_process_callbacks(device);
    assert(error == TOBII_ERROR_NO_ERROR);

    if (GetKeyState(VK_ESCAPE) & 0x8000)
    break;
    }

    error = tobii_eye_position_normalized_unsubscribe(device);
    assert(error == TOBII_ERROR_NO_ERROR);

    error = tobii_device_destroy(device);
    assert(error == TOBII_ERROR_NO_ERROR);

    error = tobii_api_destroy(api);
    assert(error == TOBII_ERROR_NO_ERROR);
    return 0;
    }

    Thanks,
    Chaim

    #11861
    Grant [Tobii]
    Keymaster

    Hi @chaimdryzun1980, thanks for sharing the code. The technique and trigonometry for determining the pupillary distance looks OK. What kind of values are you getting and how much variance according to distance from eye tracker? Would be interesting to see a graph showing your PD in relation to ET distance. Indeed, there is expected to be some variance within tolerance so if you need a final value, it would seem reasonable to take an average value over a given time and space window.

Viewing 5 posts - 1 through 5 (of 5 total)
  • You must be logged in to reply to this topic.