Blink Removal From Pupil Diameter Data

When dealing with gaze data, a velocity-based filter is typically used to identify fixations from raw samples. In this article I will talk about using a similar filter to identify blinks and other artifacts in pupil diameter data. I have seen this procedure described in an article by Mathôt (2013).

Basically, the algorithm should calculate sample-to-sample velocity of change in pupil diameter and then identify samples that decrease in diameter at a speed above the threshold (blink onset), then increase at a speed above the threshold (reversal) then go back to changing slowly, or at a speed below the threshold (offset). So a blink “corresponds to an onset, reversal, and offset, necessarily in that order.” (Mathôt, 2013)

After trying to reproduce the algorithm described above to use it on my data (collected using Tobii Pro Glasses 2), I noticed that the procedure is not as straightforward as it seems. I rarely had the three stages described above (onset, reversal and offset). Instead, I often had an onset of a blink followed by some missing samples, or some missing samples followed by what seems to be the reversal stage of a blink and so on. This could be due to noise in the data introduced by the natural setting and the relatively low sampling rate at which my data was collected (50 Hz).

I tried to modify the algorithm to account for such patterns in the data. The logic, in addition to that provided by Mathôt (2013), is to check for blink ‘reversals’ preceded by some missing samples for a duration that does not exceed that of a typical blink (between 100 and 400ms). Additionally, checking for blink ‘onsets’ followed by some missing samples or some  consecutive missing samples that span a duration of a typical blink could also be useful, but I haven’t implemented these in the example (yet). Results of my attempt can be seen in Figure 1.

example_blink_detection
Figure 1: Raw pupil diameter data in millimeters (top) and the same data with blinks removed using a filter based on Mathot’s algorithm (bottom).

Then I tried to implement a simpler filter that detects artifacts based on a velocity threshold (which includ blinks), and I obtained similar results for blinks (Figure 2). I also got rid of spikes in my data that can influence data analysis, which can be seen in the example linked below.

example_artifact_detection
Figure 2: Raw pupil diameter data in millimeter (top) and the same data with blinks removed using a simple velocity-based filter (bottom)

I used R for the example linked below, but the procedure can be ported to any other language. To simplify this example I used pupil data from one eye only. I think the procedure should be repeated for both pupils, if the data is available, before going on to average the pupil data.

You can check the article I wrote about pupil analysis to see an example of how to filter pupil data and average the diameter from both pupils.

Sample data and the processing script can be found on github. I added both filters to my rGaze project, and they can be downloaded here. You can try the filter on your data and tell me what you think; It is very easy!

If you have suggestions or if you think the filter is really bad (or good), I would love to know about it. Feel free to contact me on this form, or one of my social accounts below.

Edit: You can also try the shiny app to use these filters on your own data. Follow this link to go directly to the app.