pupil#
Process and extract pupil
Sketch of default strategy:
Track to find approximate position of eyes with
processors.Haar_TrackerMask image around both eyes, split processing in parallel L/R (if present)
Use white of eyes to mask cornea and pupil
Sigmoid filter images to separate cornea and pupil
Blob detection to find center mass of pupil
Compare blob vs. edge detection of pupil.
Use Kalman filter on
perceptivo.types.units.Ellipseproperties to avoid jumps and all that
- class perceptivo.video.pupil.PupilExtractor(preprocessor: Optional[perceptivo.video.pupil.Preprocessor] = None, filter: Optional[perceptivo.video.pupil.PupilFilter] = None, **kwargs)#
Bases:
perceptivo.root.Perceptivo_ObjectBase class for pupil extraction strategies.
- process(frame: perceptivo.types.video.Frame) Optional[perceptivo.types.pupil.Pupil]#
Call
preprocess()and then_process(), returning a Pupil estimate- Parameters
frame (
types.video.Frame) – Frame to process- Returns
types.pupil.PupilPupil Estimate
- abstract _process(frame: perceptivo.types.video.Frame) perceptivo.types.pupil.Pupil#
Given a frame, extract a pupil estimate
- Parameters
frame (
types.video.Frame) – Frame to process!- Returns
Estimated Pupil!
- Return type
- class perceptivo.video.pupil.PupilFilter(**kwargs)#
Bases:
perceptivo.root.Perceptivo_ObjectBase class for filtering pupil tracks – for example by using a Kalman filter to filter erroneous pupil detections from a
PupilExtractor.PupilFilters should be given to the
PupilExtractoras its filter argument, and should be called last in thePupilExtractor.process()method.Each subclass should implement a
_processmethod that takes and returns aPupilobject.- process(pupil: perceptivo.types.pupil.Pupil) perceptivo.types.pupil.Pupil#
- class perceptivo.video.pupil.Preprocessor(**kwargs)#
Bases:
perceptivo.root.Perceptivo_ObjectBase class for preprocessing images before they reach the main
PupilExtractor.process()method.Each subclass should implement a
processmethod that takes and returns aFrameobject.- abstract process(frame: perceptivo.types.video.Frame) perceptivo.types.video.Frame#
- class perceptivo.video.pupil.EllipseExtractor_Params(*, footprint_size: int = 5, search_scale: float = 1.5)#
Bases:
pydantic.main.BaseModelCreate a new model by parsing and validating input data from keyword arguments.
Raises ValidationError if the input data cannot be parsed to form a valid model.
- class perceptivo.video.pupil.EllipseExtractor(footprint_size: int = 5, search_scale: float = 1.5, **kwargs)#
Bases:
perceptivo.video.pupil.PupilExtractorVery simple extractor that estimates an ellipse from the edges of a pupil. This extractor assumes that the
Framegiven to it has very high contrast, ie. that the rest of the face is essentially white and the pupil and cornea are the only colored things in the image.In order
Median Filter to smooth image -
skimage.filters.rank.median()Scharr Filter to detect edges -
skimage.filters.scharr()Get the otsu threshold on the scharr filtered image -
skimage.filters.threshold_otsu()Skeletonize the pixels above the threshold -
skimage.morphology.skeletonize()Label the independent edges -
skimage.measure.label()If present, use the
types.units.EllipsefromPupilExtractor.filter.last_pupilto select only those edges within the ellipse (scaled bysearch_scale)Estimate ellipses from remaining edges -
skimage.measure.EllipseModelKeep the ellipses with the lowest median pixel value (presumably the pupil is dark)
Return a
Pupilobject.
References
Read a few years ago, might be worth revisiting: https://cdn.intechopen.com/pdfs/33559/InTech-Methods_for_ellipse_detection_from_edge_maps_of_real_images.pdf
- Parameters
footprint_size (int) – Diameter of footprint (a
skimage.morphology.disk()) used in the median filterskimage.filters.rank.median(). This should be roughly the size of the pupil.search_scale (float) – If present, how much to scale the
PupilExtractor.filter.last_pupilto select edges before fitting ellipses. Eg.1.5enlarges the last ellipse by 1.5 and rejects all edges outside of that radius.**kwargs ()
- __init__(footprint_size: int = 5, search_scale: float = 1.5, **kwargs)#
- Parameters
footprint_size (int) – Diameter of footprint (a
skimage.morphology.disk()) used in the median filterskimage.filters.rank.median(). This should be roughly the size of the pupil.search_scale (float) – If present, how much to scale the
PupilExtractor.filter.last_pupilto select edges before fitting ellipses. Eg.1.5enlarges the last ellipse by 1.5 and rejects all edges outside of that radius.**kwargs ()
- property footprint_size: int#
As described in the
attrdocstring. When setting a footprint size, remake thefootprint- Returns
int
- filter_edges(edges: numpy.ndarray) numpy.ndarray#
Set all edges outside of a search radius, given our previous ellipse, to zero
- choose_ellipse(edges: numpy.ndarray, frame: numpy.ndarray) Optional[skimage.measure.fit.EllipseModel]#
Given an array of edge labels (from
skimage.morphology.label()), usually from_process(), return anskimage.measure.EllipseModel, choose the one that is the pupil- Parameters
edges () – An array of image labels, ie. an array of ints where background == 0, edge 1 == 1, and so on.
frame () – The original or filtered image frame (the array, not the
Frameobject)
- Returns
the most pupil-like ellipse
- Return type
- class perceptivo.video.pupil.EnsembleExtractor_NonIR(sigmoid=(0.5, 5), canny_kwargs: Optional[dict] = None, hough_kwargs: Optional[dict] = None, *args, **kwargs)#
Bases:
perceptivo.video.pupil.PupilExtractorExtractor that uses an ensemble of techniques to track a pupil.
Written before realizing the trakcing problem was much easier using IR! Kept to mine parts from before discontinuing
Track to find approximate position of eyes with
processors.Haar_TrackerMask image around both eyes, split processing in parallel L/R (if present)
Use white of eyes to mask cornea and pupil
Sigmoid filter images to separate cornea and pupil
Blob detection to find center mass of pupil
Compare blob vs. edge detection of pupil.
Use Kalman filter on
perceptivo.types.units.Ellipseproperties to avoid jumps and all that
- preprocess(frame: perceptivo.types.video.Frame) perceptivo.types.video.Frame#
- class perceptivo.video.pupil.Pupil_Extractors(value)#
Bases:
enum.EnumAn enumeration.
- simple = <class 'perceptivo.video.pupil.EllipseExtractor'>#
- perceptivo.video.pupil.get_extractor(extractor=<enum 'Pupil_Extractors'>) Type[perceptivo.video.pupil.EllipseExtractor]#
- Parameters
extractor (str,
Pupil_Extractors) – str corresponding to one of the entries inPupil_Extractors, eg'simple'
Returns: