mirror of
https://github.com/EyeTrackVR/EyeTrackVR.git
synced 2025-11-04 14:39:42 +08:00
Merge branch 'HSF-and-new-algos-feature-branch' of https://github.com/RedHawk989/EyeTrackVR into HSF-and-new-algos-feature-branch
This commit is contained in:
commit
c26c336a3e
176
EyeTrackApp/enums.py
Normal file
176
EyeTrackApp/enums.py
Normal file
@ -0,0 +1,176 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import types
|
||||
from collections import namedtuple
|
||||
from typing import Any, ClassVar, Dict, List, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Iterator, Mapping
|
||||
|
||||
__all__ = (
|
||||
'Enum',
|
||||
# 'EyeId',
|
||||
'EyeLR',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
def _create_value_cls(name: str, comparable: bool):
|
||||
# All the type ignores here are due to the type checker being unable to recognise
|
||||
# Runtime type creation without exploding.
|
||||
cls = namedtuple('_EnumValue_' + name, 'name value')
|
||||
cls.__repr__ = lambda self: f'<{name}.{self.name}: {self.value!r}>' # type: ignore
|
||||
cls.__str__ = lambda self: f'{name}.{self.name}' # type: ignore
|
||||
if comparable:
|
||||
cls.__le__ = lambda self, other: isinstance(other, self.__class__) and self.value <= other.value # type: ignore
|
||||
cls.__ge__ = lambda self, other: isinstance(other, self.__class__) and self.value >= other.value # type: ignore
|
||||
cls.__lt__ = lambda self, other: isinstance(other, self.__class__) and self.value < other.value # type: ignore
|
||||
cls.__gt__ = lambda self, other: isinstance(other, self.__class__) and self.value > other.value # type: ignore
|
||||
return cls
|
||||
|
||||
|
||||
def _is_descriptor(obj):
|
||||
return hasattr(obj, '__get__') or hasattr(obj, '__set__') or hasattr(obj, '__delete__')
|
||||
|
||||
|
||||
class EnumMeta(type):
|
||||
if TYPE_CHECKING:
|
||||
__name__: ClassVar[str]
|
||||
_enum_member_names_: ClassVar[List[str]]
|
||||
_enum_member_map_: ClassVar[Dict[str, Any]]
|
||||
_enum_value_map_: ClassVar[Dict[Any, Any]]
|
||||
|
||||
def __new__(cls, name: str, bases: Tuple[type, ...], attrs: Dict[str, Any], *, comparable: bool = False) -> Self:
|
||||
value_mapping = {}
|
||||
member_mapping = {}
|
||||
member_names = []
|
||||
|
||||
value_cls = _create_value_cls(name, comparable)
|
||||
for key, value in list(attrs.items()):
|
||||
is_descriptor = _is_descriptor(value)
|
||||
if key[0] == '_' and not is_descriptor:
|
||||
continue
|
||||
|
||||
# Special case classmethod to just pass through
|
||||
if isinstance(value, classmethod):
|
||||
continue
|
||||
|
||||
if is_descriptor:
|
||||
setattr(value_cls, key, value)
|
||||
del attrs[key]
|
||||
continue
|
||||
|
||||
try:
|
||||
new_value = value_mapping[value]
|
||||
except KeyError:
|
||||
new_value = value_cls(name=key, value=value)
|
||||
value_mapping[value] = new_value
|
||||
member_names.append(key)
|
||||
|
||||
member_mapping[key] = new_value
|
||||
attrs[key] = new_value
|
||||
|
||||
attrs['_enum_value_map_'] = value_mapping
|
||||
attrs['_enum_member_map_'] = member_mapping
|
||||
attrs['_enum_member_names_'] = member_names
|
||||
attrs['_enum_value_cls_'] = value_cls
|
||||
actual_cls = super().__new__(cls, name, bases, attrs)
|
||||
value_cls._actual_enum_cls_ = actual_cls # type: ignore # Runtime attribute isn't understood
|
||||
return actual_cls
|
||||
|
||||
def __iter__(cls) -> Iterator[Any]:
|
||||
return (cls._enum_member_map_[name] for name in cls._enum_member_names_)
|
||||
|
||||
def __reversed__(cls) -> Iterator[Any]:
|
||||
return (cls._enum_member_map_[name] for name in reversed(cls._enum_member_names_))
|
||||
|
||||
def __len__(cls) -> int:
|
||||
return len(cls._enum_member_names_)
|
||||
|
||||
def __repr__(cls) -> str:
|
||||
return f'<enum {cls.__name__}>'
|
||||
|
||||
@property
|
||||
def __members__(cls) -> Mapping[str, Any]:
|
||||
return types.MappingProxyType(cls._enum_member_map_)
|
||||
|
||||
def __call__(cls, value: str) -> Any:
|
||||
try:
|
||||
return cls._enum_value_map_[value]
|
||||
except (KeyError, TypeError):
|
||||
raise ValueError(f"{value!r} is not a valid {cls.__name__}")
|
||||
|
||||
def __getitem__(cls, key: str) -> Any:
|
||||
return cls._enum_member_map_[key]
|
||||
|
||||
def __setattr__(cls, name: str, value: Any) -> None:
|
||||
raise TypeError('Enums are immutable.')
|
||||
|
||||
def __delattr__(cls, attr: str) -> None:
|
||||
raise TypeError('Enums are immutable')
|
||||
|
||||
def __instancecheck__(self, instance: Any) -> bool:
|
||||
# isinstance(x, Y)
|
||||
# -> __instancecheck__(Y, x)
|
||||
try:
|
||||
return instance._actual_enum_cls_ is self
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from enum import Enum
|
||||
else:
|
||||
class Enum(metaclass=EnumMeta):
|
||||
@classmethod
|
||||
def try_value(cls, value):
|
||||
try:
|
||||
return cls._enum_value_map_[value]
|
||||
except (KeyError, TypeError):
|
||||
return value
|
||||
|
||||
E = TypeVar('E', bound='Enum')
|
||||
|
||||
def create_unknown_value(cls: Type[E], val: Any) -> E:
|
||||
value_cls = cls._enum_value_cls_ # type: ignore # This is narrowed below
|
||||
name = f'unknown_{val}'
|
||||
return value_cls(name=name, value=val)
|
||||
|
||||
|
||||
def try_enum(cls: Type[E], val: Any) -> E:
|
||||
"""A function that tries to turn the value into enum ``cls``.
|
||||
If it fails it returns a proxy invalid value instead.
|
||||
"""
|
||||
|
||||
try:
|
||||
return cls._enum_value_map_[val] # type: ignore # All errors are caught below
|
||||
except (KeyError, TypeError, AttributeError):
|
||||
return create_unknown_value(cls, val)
|
||||
|
||||
|
||||
# The line above is based on the code in the following url
|
||||
# https://github.com/Rapptz/discord.py/blob/f7e97954950ffb0e34238d70813454caa6f1a3ae/discord/enums.py
|
||||
|
||||
|
||||
# class EyeId(Enum):
|
||||
# # https://docs.python.org/3.9/library/enum.html#functional-api
|
||||
# # > The reason for defaulting to 1 as the starting number and not 0 is that 0 is False in a boolean sense, but enum members all evaluate to True.
|
||||
# RIGHT = 1
|
||||
# LEFT = 2
|
||||
# BOTH = 3
|
||||
# SETTINGS = 4
|
||||
#
|
||||
# def __str__(self) -> str:
|
||||
# return self.name
|
||||
#
|
||||
# def __int__(self) -> int:
|
||||
# return self.value
|
||||
|
||||
class EyeLR(Enum):
|
||||
LEFT = 1
|
||||
RIGHT = 2
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def __int__(self) -> int:
|
||||
return self.value
|
||||
@ -48,6 +48,7 @@ from enum import Enum
|
||||
from one_euro_filter import OneEuroFilter
|
||||
from utils.misc_utils import PlaySound, SND_FILENAME, SND_ASYNC
|
||||
import importlib
|
||||
from osc import EyeId
|
||||
from osc_calibrate_filter import *
|
||||
from haar_surround_feature import External_Run_HSF
|
||||
from blob import *
|
||||
@ -150,6 +151,9 @@ class EyeProcessor:
|
||||
self.er_hsf = None
|
||||
self.er_hsrac = None
|
||||
|
||||
self.ibo = IntensityBasedOpeness(eyeside=EyeLR.LEFT if self.eye_id is EyeId.LEFT else EyeLR.RIGHT if eye_id is EyeId.RIGHT else -1)
|
||||
self.roi_include_set = {"rotation_angle", "roi_window_x", "roi_window_y"}
|
||||
|
||||
self.failed = 0
|
||||
|
||||
self.skip_blink_detect = False
|
||||
@ -209,6 +213,7 @@ class EyeProcessor:
|
||||
self.config.roi_window_x + self.config.roi_window_w
|
||||
),
|
||||
]
|
||||
self.ibo.change_roi(self.config.dict(include=self.roi_include_set))
|
||||
|
||||
except:
|
||||
# Failure to process frame, reuse previous frame.
|
||||
@ -253,7 +258,8 @@ class EyeProcessor:
|
||||
# if (cx - self.prev_x) <= 45 and (cy - self.prev_y) <= 45 :
|
||||
# self.prev_x = cx
|
||||
# self.prev_y = cy
|
||||
self.eyeopen = intense(cx, cy, uncropframe, self.eye_id)
|
||||
# self.eyeopen = intense(cx, cy, uncropframe, self.eye_id)
|
||||
self.eyeopen = self.ibo.intense(cx,cy,uncropframe)
|
||||
out_x, out_y = cal_osc(self, cx, cy)
|
||||
#print(self.eyeoffx, self.eyeopen)
|
||||
|
||||
@ -267,7 +273,7 @@ class EyeProcessor:
|
||||
def HSFM(self):
|
||||
# todo: added process to initialise er_hsf when resolution changes
|
||||
cx, cy, frame = self.er_hsf.run(self.current_image_gray)
|
||||
self.eyeopen = intense(cx, cy, self.current_image_gray)
|
||||
self.eyeopen = self.ibo.intense(cx, cy, self.current_image_gray)
|
||||
out_x, out_y = cal_osc(self, cx, cy)
|
||||
if cx == 0:
|
||||
self.output_images_and_update(frame, EyeInformation(InformationOrigin.HSF, out_x, out_y, 0, self.eyeopen)) #update app
|
||||
@ -276,7 +282,7 @@ class EyeProcessor:
|
||||
|
||||
def RANSAC3DM(self):
|
||||
cx, cy, thresh = RANSAC3D(self)
|
||||
self.eyeopen = intense(cx, cy, self.current_image_gray)
|
||||
self.eyeopen = self.ibo.intense(cx, cy, self.current_image_gray)
|
||||
out_x, out_y = cal_osc(self, cx, cy)
|
||||
if cx == 0:
|
||||
self.output_images_and_update(thresh, EyeInformation(InformationOrigin.RANSAC, out_x, out_y, 0, self.eyeopen)) #update app
|
||||
@ -285,7 +291,7 @@ class EyeProcessor:
|
||||
|
||||
def BLOBM(self):
|
||||
cx, cy, thresh = BLOB(self)
|
||||
self.eyeopen = intense(cx, cy, self.current_image_gray)
|
||||
self.eyeopen = self.ibo.intense(cx, cy, self.current_image_gray)
|
||||
out_x, out_y = cal_osc(self, cx, cy)
|
||||
if cx == 0:
|
||||
self.output_images_and_update(thresh, EyeInformation(InformationOrigin.HSRAC, out_x, out_y, 0, self.eyeopen)) #update app
|
||||
|
||||
@ -2,17 +2,11 @@ import numpy as np
|
||||
import time
|
||||
import os
|
||||
import cv2
|
||||
from enum import IntEnum
|
||||
from osc import EyeId
|
||||
from enums import EyeLR
|
||||
#higher intensity means more closed/ more white/less pupil
|
||||
|
||||
#Hm I need an acronym for this, any ideas?
|
||||
#IBO Intensity Based Openess
|
||||
class EyeId(IntEnum):
|
||||
RIGHT = 0
|
||||
LEFT = 1
|
||||
BOTH = 2
|
||||
SETTINGS = 3
|
||||
#IBO Intensity Based Openess
|
||||
|
||||
# HOW THIS WORKS:
|
||||
# we get the intensity of pupil area from HSF crop, When the eyelid starts to close, the pupil starts being obstructed by skin which is generally lighter than the pupil.
|
||||
@ -26,12 +20,6 @@ class EyeId(IntEnum):
|
||||
# https://stackoverflow.com/questions/43185605/how-do-i-read-an-image-from-a-path-with-unicode-characters
|
||||
# https://github.com/opencv/opencv/issues/18305
|
||||
|
||||
|
||||
|
||||
lct = time.time()
|
||||
data = None
|
||||
|
||||
|
||||
def csv2data(frameshape, filepath):
|
||||
# For data checking
|
||||
frameshape = (frameshape[0], frameshape[1]+1)
|
||||
@ -50,6 +38,7 @@ def csv2data(frameshape, filepath):
|
||||
out[xy_list[:, 1], xy_list[:, 0]] = val_list[:]
|
||||
return out
|
||||
|
||||
|
||||
def data2csv(data_u32, filepath):
|
||||
# For data checking
|
||||
nonzero_index = np.nonzero(data_u32) #(row,col)
|
||||
@ -84,130 +73,151 @@ def newdata(frameshape):
|
||||
return np.zeros(frameshape, dtype=np.uint32)
|
||||
|
||||
|
||||
def check_and_load(frameshape, now_data, fname):
|
||||
req_newdata = False
|
||||
# Not very clever, but increase the width by 1px to save the maximum value.
|
||||
frameshape = (frameshape[0], frameshape[1]+1)
|
||||
if now_data is None:
|
||||
print("Load data for blinking: {}".format(fname))
|
||||
if os.path.isfile(fname):
|
||||
img = cv2.imread(fname, flags=cv2.IMREAD_UNCHANGED)
|
||||
if img.shape[:2] != frameshape:
|
||||
print("size does not match the input frame.")
|
||||
req_newdata = True
|
||||
else:
|
||||
now_data = u16_u32_3ch_1ch(img)
|
||||
else:
|
||||
print("File does not exist.")
|
||||
req_newdata = True
|
||||
else:
|
||||
if now_data.shape != frameshape:
|
||||
# Using the previous and current frame sizes and centre positions from the original, etc., the data can be ported to some extent, but there may be many areas where code changes are required.
|
||||
print("Frame size changed.")
|
||||
req_newdata = True
|
||||
if req_newdata:
|
||||
now_data = newdata(frameshape)
|
||||
|
||||
# data2csv(now_data, "a.csv")
|
||||
# csv2data(frameshape,"a.csv")
|
||||
return now_data
|
||||
|
||||
|
||||
def intense(x, y, frame, eye_id):
|
||||
global lct, data
|
||||
e = False
|
||||
if eye_id in [EyeId.RIGHT]: #TODO run only once
|
||||
fname = "IBO_RIGHT.png"
|
||||
eye = "RIGHT"
|
||||
if eye_id in [EyeId.LEFT]:
|
||||
fname = "IBO_LEFT.png"
|
||||
eye = "LEFT"
|
||||
|
||||
# 0 in data is used as the initial value.
|
||||
# When assigning a value, +1 is added to the value to be assigned.
|
||||
data = check_and_load(frame.shape[:2], data, fname)
|
||||
int_x, int_y = int(x), int(y)
|
||||
|
||||
# upper_x = min(int_x + 25, frame.shape[1]) #TODO make this a setting
|
||||
#lower_x = max(int_x - 25, 0)
|
||||
#upper_y = min(int_y + 25, frame.shape[0])
|
||||
#lower_y = max(int_y - 25, 0)
|
||||
|
||||
#frame_crop = frame[lower_y:upper_y, lower_x:upper_x]
|
||||
frame_crop = frame
|
||||
|
||||
# The same can be done with cv2.integral, but since there is only one area of the rectangle for which we want to know the total value, there is no advantage in terms of computational complexity.
|
||||
intensity = frame_crop.sum()+1
|
||||
# numpy:np.sum(),ndarray.sum()
|
||||
# opencv:cv2.sumElems()
|
||||
# I don't know which is faster.
|
||||
#print(frame.shape[1], frame.shape[0], int_x, int_y, eye)
|
||||
changed = False
|
||||
newval_flg = False
|
||||
if int_y >= frame.shape[0]:
|
||||
# data_val = 1
|
||||
int_y = frame.shape[0] - 1
|
||||
e = True
|
||||
print('CAUGHT Y OUT OF BOUNDS')
|
||||
|
||||
if int_x >= frame.shape[1]:
|
||||
# data_val = 1
|
||||
e = True
|
||||
int_x = frame.shape[0] - 1
|
||||
print('CAUGHT X OUT OF BOUNDS')
|
||||
|
||||
#if e == False: #TODO clean this up
|
||||
class IntensityBasedOpeness:
|
||||
def __init__(self, eyeside: EyeLR):
|
||||
# todo: It is necessary to consider whether the filename can be changed in the configuration file, etc.
|
||||
self.imgfile = "IBO_LEFT.png" if eyeside is EyeLR.LEFT else "IBO_RIGHT.png"
|
||||
# self.data[0, -1] = maxval, [1, -1] = rotation, [2, -1] = x, [3, -1] = y
|
||||
self.data = None
|
||||
self.lct = None
|
||||
self.maxval = 0
|
||||
# self.img_roi = self.now_roi == {"rotation": 0, "x": 0, "y": 0}
|
||||
self.img_roi = np.zeros(3, dtype=np.int32)
|
||||
self.now_roi = np.zeros(3, dtype=np.int32)
|
||||
|
||||
data_val = data[int_y, int_x]
|
||||
|
||||
|
||||
# max pupil per cord
|
||||
if data_val == 0:
|
||||
# The value of the specified coordinates has not yet been recorded.
|
||||
data[int_y, int_x] = intensity
|
||||
changed = True
|
||||
newval_flg = True
|
||||
elif intensity < data_val: # if current intensity value is less (more pupil), save that
|
||||
data[int_y, int_x] = intensity # set value
|
||||
changed = True
|
||||
print("var adjusted")
|
||||
else:
|
||||
intensitya = max(data_val - 3, 1) # if current intensity value is less (more pupil), save that
|
||||
data[int_y, int_x] = intensitya # set value
|
||||
changed = True
|
||||
|
||||
# min pupil global
|
||||
if data[0, -1] == 0: # that value is not yet saved
|
||||
data[0, -1] = intensity # set value at 0 index
|
||||
changed = True
|
||||
print("create max", intensity)
|
||||
elif intensity > data[0, -1]: # if current intensity value is more (less pupil), save that NOTE: we have the
|
||||
data[0, -1] = intensity # set value at 0 index
|
||||
changed = True
|
||||
print("new max", intensity)
|
||||
else:
|
||||
intensityd = max(data[0, -1] - 10, 1) #continuously adjust closed intensity, will be set when user blink, used to allow eyes to close when lighting changes
|
||||
data[0, -1] = intensityd # set value at 0 index
|
||||
changed = True
|
||||
def check(self, frameshape):
|
||||
# 0 in data is used as the initial value.
|
||||
# When assigning a value, +1 is added to the value to be assigned.
|
||||
self.load(frameshape)
|
||||
# self.maxval = self.data[0, -1]
|
||||
if self.lct is None:
|
||||
self.lct = time.time()
|
||||
|
||||
if newval_flg:
|
||||
# Do the same thing as in the original version.
|
||||
print('[INFO] Something went wrong, assuming blink.')
|
||||
eyeopen = 0.7
|
||||
else:
|
||||
maxp = data[int_y, int_x]
|
||||
minp = data[0, -1]
|
||||
diffp = minp - maxp if (minp - maxp) != 0 else 1
|
||||
eyeopen = (intensity - maxp) / diffp
|
||||
eyeopen = 1 - eyeopen
|
||||
#eyeopen = eyeopen - 0.2
|
||||
# print(intensity, maxp, minp, x, y)
|
||||
# print(f"EYEOPEN: {eyeopen}")
|
||||
# print(int(x), int(y), eyeopen, maxp, minp)
|
||||
print(data[0, -1])
|
||||
if changed and ((time.time() - lct) > 4): # save every 4 seconds if something changed to save disk usage
|
||||
cv2.imwrite(fname, u32_u16_1ch3ch(data))
|
||||
lct = time.time()
|
||||
print("SAVED")
|
||||
def load(self, frameshape):
|
||||
req_newdata = False
|
||||
# Not very clever, but increase the width by 1px to save the maximum value.
|
||||
frameshape = (frameshape[0], frameshape[1] + 1)
|
||||
if self.data is None:
|
||||
print("Load data for blinking: {}".format(self.imgfile))
|
||||
if os.path.isfile(self.imgfile):
|
||||
try:
|
||||
img = cv2.imread(self.imgfile, flags=cv2.IMREAD_UNCHANGED)
|
||||
if img.shape[:2] != frameshape:
|
||||
print("size does not match the input frame.")
|
||||
req_newdata = True
|
||||
else:
|
||||
self.data = u16_u32_3ch_1ch(img)
|
||||
self.img_roi[:] = self.data[1:4, -1]
|
||||
if not np.array_equal(self.img_roi, self.now_roi):
|
||||
# If the ROI recorded in the image file differs from the current ROI
|
||||
req_newdata = True
|
||||
else:
|
||||
self.maxval = self.data[0, -1]
|
||||
except:
|
||||
print("File read error: {}".format(self.imgfile))
|
||||
req_newdata = True
|
||||
else:
|
||||
print("File does not exist.")
|
||||
req_newdata = True
|
||||
else:
|
||||
if self.data.shape != frameshape or not np.array_equal(self.img_roi, self.now_roi):
|
||||
# If the ROI recorded in the image file differs from the current ROI
|
||||
#todo: Using the previous and current frame sizes and centre positions from the original, etc., the data can be ported to some extent, but there may be many areas where code changes are required.
|
||||
print("Frame size changed.")
|
||||
req_newdata = True
|
||||
if req_newdata:
|
||||
self.data = newdata(frameshape)
|
||||
self.maxval = 0
|
||||
self.img_roi = self.now_roi.copy()
|
||||
# data2csv(self.data, "a.csv")
|
||||
# csv2data(frameshape,"a.csv")
|
||||
|
||||
def save(self):
|
||||
self.data[0, -1] = self.maxval
|
||||
self.data[1:4, -1] = self.now_roi
|
||||
cv2.imwrite(self.imgfile, u32_u16_1ch3ch(self.data))
|
||||
print("SAVED: {}".format(self.imgfile))
|
||||
|
||||
def change_roi(self, roiinfo: dict):
|
||||
self.now_roi[:] = [v for v in roiinfo.values()]
|
||||
|
||||
def intense(self, x, y, frame):
|
||||
self.check(frame.shape)
|
||||
int_x, int_y = int(x), int(y)
|
||||
|
||||
# upper_x = min(int_x + 25, frame.shape[1]) #TODO make this a setting
|
||||
# lower_x = max(int_x - 25, 0)
|
||||
# upper_y = min(int_y + 25, frame.shape[0])
|
||||
# lower_y = max(int_y - 25, 0)
|
||||
|
||||
return eyeopen
|
||||
# frame_crop = frame[lower_y:upper_y, lower_x:upper_x]
|
||||
frame_crop = frame
|
||||
|
||||
# The same can be done with cv2.integral, but since there is only one area of the rectangle for which we want to know the total value, there is no advantage in terms of computational complexity.
|
||||
intensity = frame_crop.sum() + 1
|
||||
# numpy:np.sum(),ndarray.sum()
|
||||
# opencv:cv2.sumElems()
|
||||
# I don't know which is faster.
|
||||
# print(frame.shape[1], frame.shape[0], int_x, int_y, eye)
|
||||
changed = False
|
||||
newval_flg = False
|
||||
if int_y >= frame.shape[0]:
|
||||
# data_val = 1
|
||||
int_y = frame.shape[0] - 1
|
||||
print('CAUGHT Y OUT OF BOUNDS')
|
||||
|
||||
if int_x >= frame.shape[1]:
|
||||
# data_val = 1
|
||||
int_x = frame.shape[0] - 1
|
||||
print('CAUGHT X OUT OF BOUNDS')
|
||||
|
||||
data_val = self.data[int_y, int_x]
|
||||
|
||||
# max pupil per cord
|
||||
if data_val == 0:
|
||||
# The value of the specified coordinates has not yet been recorded.
|
||||
self.data[int_y, int_x] = intensity
|
||||
changed = True
|
||||
newval_flg = True
|
||||
else:
|
||||
if intensity < data_val: # if current intensity value is less (more pupil), save that
|
||||
self.data[int_y, int_x] = intensity # set value
|
||||
changed = True
|
||||
print("var adjusted")
|
||||
else:
|
||||
intensitya = max(data_val - 3, 1) # if current intensity value is less (more pupil), save that
|
||||
self.data[int_y, int_x] = intensitya # set value
|
||||
changed = True
|
||||
|
||||
# min pupil global
|
||||
if self.maxval == 0: # that value is not yet saved
|
||||
self.maxval = intensity # set value at 0 index
|
||||
print("create max", intensity)
|
||||
else:
|
||||
if intensity > self.maxval: # if current intensity value is more (less pupil), save that NOTE: we have the
|
||||
self.maxval = intensity # set value at 0 index
|
||||
print("new max", intensity)
|
||||
else:
|
||||
intensityd = max(self.maxval - 10, 1) # continuously adjust closed intensity, will be set when user blink, used to allow eyes to close when lighting changes
|
||||
self.maxval = intensityd # set value at 0 index
|
||||
|
||||
if newval_flg:
|
||||
# Do the same thing as in the original version.
|
||||
print('[INFO] Something went wrong, assuming blink.')
|
||||
eyeopen = 0.7
|
||||
else:
|
||||
maxp = self.data[int_y, int_x]
|
||||
minp = self.maxval
|
||||
diffp = minp - maxp if (minp - maxp) != 0 else 1
|
||||
eyeopen = (intensity - maxp) / diffp
|
||||
eyeopen = 1 - eyeopen
|
||||
# eyeopen = eyeopen - 0.2
|
||||
# print(intensity, maxp, minp, x, y)
|
||||
# print(f"EYEOPEN: {eyeopen}")
|
||||
# print(int(x), int(y), eyeopen, maxp, minp)
|
||||
# print(self.data[0, -1])
|
||||
# print(self.maxval)
|
||||
if changed and ((time.time() - self.lct) > 4): # save every 4 seconds if something changed to save disk usage
|
||||
self.save()
|
||||
self.lct = time.time()
|
||||
return eyeopen
|
||||
|
||||
Loading…
Reference in New Issue
Block a user