mirror of
https://github.com/EyeTrackVR/EyeTrackVR.git
synced 2025-11-04 14:39:42 +08:00
Merge Conflicts
This commit is contained in:
commit
97616d4fdf
1
.gitignore
vendored
1
.gitignore
vendored
@ -23,3 +23,4 @@ EyeTrackApp/IBO_RIGHT.png
|
||||
/IBO_LEFT.png
|
||||
/eyetrack_settings.backup
|
||||
/eyetrack_settings.json
|
||||
zBuild.bat
|
||||
|
||||
@ -222,6 +222,13 @@ class EyeTrackSettingsConfig(BaseModel):
|
||||
gui_eyetune_maxout: float = 1
|
||||
gui_eyetune_maxup: float = 1
|
||||
gui_eyetune_maxdown: float = 1
|
||||
#SmartInversionTracking
|
||||
gui_smartinversion_enabled: bool = False
|
||||
gui_smartinversion_select_right: bool = True
|
||||
gui_smartinversion_thresh: float = 0.4
|
||||
gui_smartinversion_frame_count: int = 30
|
||||
gui_smartinversion_smoothing_rate: float = 0.025
|
||||
gui_smartinversion_minthresh: float = 0.3
|
||||
|
||||
class EyeTrackConfig(BaseModel):
|
||||
version: int = 1
|
||||
|
||||
@ -29,6 +29,7 @@ import time
|
||||
from enum import IntEnum
|
||||
from utils.misc_utils import PlaySound, SND_FILENAME, SND_ASYNC, resource_path
|
||||
from utils.eye_falloff import velocity_falloff
|
||||
from utils.smart_inversion import smart_inversion
|
||||
import socket
|
||||
import struct
|
||||
import threading
|
||||
@ -336,7 +337,10 @@ class cal:
|
||||
var.past_x = out_x_mult
|
||||
var.past_y = out_y_mult
|
||||
|
||||
out_x, out_y = velocity_falloff(self, var, out_x, out_y)
|
||||
if(self.settings.gui_smartinversion_enabled):
|
||||
out_x, out_y = smart_inversion(self,var, out_x, out_y)
|
||||
else:
|
||||
out_x, out_y = velocity_falloff(self, var, out_x, out_y)
|
||||
|
||||
#Clamps the right eye's X values
|
||||
if self.eye_id == EyeId.LEFT:
|
||||
|
||||
@ -32,6 +32,7 @@ from settings.modules.GeneralSettingsModule import GeneralSettingsModule
|
||||
from settings.modules.OneEuroSettingsModule import OneEuroSettingsModule
|
||||
from settings.modules.OSCSettingsModule import OSCSettingsModule
|
||||
from settings.modules.EyeTuneSettingsModule import EyeTuneSettingsModule
|
||||
from settings.modules.SmartInversionSettingsModule import SmartInversionSettingsModule
|
||||
|
||||
|
||||
class SettingsWidget(BaseSettingsWidget):
|
||||
@ -39,6 +40,7 @@ class SettingsWidget(BaseSettingsWidget):
|
||||
settings_modules = [
|
||||
GeneralSettingsModule,
|
||||
OneEuroSettingsModule,
|
||||
SmartInversionSettingsModule,
|
||||
OSCSettingsModule,
|
||||
EyeTuneSettingsModule,
|
||||
]
|
||||
|
||||
@ -32,3 +32,12 @@ def check_is_ip_address(v: str):
|
||||
return v
|
||||
except ValueError:
|
||||
raise ValueError("Please provide a valid IP Address")
|
||||
|
||||
def try_convert_to_int(v: str):
|
||||
""""
|
||||
Checks if value provided can be converted to an integer and returns the converted result
|
||||
"""
|
||||
try:
|
||||
return int(v)
|
||||
except ValueError:
|
||||
raise ValueError("Please provide a number with no decimal points")
|
||||
110
EyeTrackApp/settings/modules/SmartInversionSettingsModule.py
Normal file
110
EyeTrackApp/settings/modules/SmartInversionSettingsModule.py
Normal file
@ -0,0 +1,110 @@
|
||||
from pydantic import AfterValidator
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from settings.modules.BaseModule import BaseSettingsModule, BaseValidationModel
|
||||
from settings.constants import BACKGROUND_COLOR
|
||||
import PySimpleGUI as sg
|
||||
|
||||
from settings.modules.CommonFieldValidators import try_convert_to_float
|
||||
from settings.modules.CommonFieldValidators import try_convert_to_int
|
||||
|
||||
class SmartInversionValidationModule(BaseValidationModel):
|
||||
gui_smartinversion_enabled: bool
|
||||
gui_smartinversion_select_right: bool
|
||||
gui_smartinversion_thresh: Annotated[float, AfterValidator(try_convert_to_float)]
|
||||
gui_smartinversion_frame_count: Annotated[int, AfterValidator(try_convert_to_int)]
|
||||
gui_smartinversion_smoothing_rate: Annotated[float, AfterValidator(try_convert_to_float)]
|
||||
gui_smartinversion_minthresh: Annotated[float, AfterValidator(try_convert_to_float)]
|
||||
|
||||
class SmartInversionSettingsModule(BaseSettingsModule):
|
||||
def __init__(self, config, widget_id, **kwargs):
|
||||
super().__init__(config=config, widget_id=widget_id, **kwargs)
|
||||
self.validation_model = SmartInversionValidationModule
|
||||
self.gui_smartinversion_enabled = f"-gui_smartinversion_enabled{widget_id}-"
|
||||
self.gui_smartinversion_select_right = f"-gui_smartinversion_select_right{widget_id}-"
|
||||
self.gui_smartinversion_thresh = f"-gui_smartinversion_thresh{widget_id}-"
|
||||
self.gui_smartinversion_frame_count =f"-gui_smartinversion_frame_count{widget_id}"
|
||||
self.gui_smartinversion_smoothing_rate =f"-gui_smartinversion_smoothing_rate{widget_id}"
|
||||
self.gui_smartinversion_minthresh =f"-gui_smartinversion_minthresh{widget_id}"
|
||||
|
||||
|
||||
|
||||
def get_layout(self):
|
||||
return [
|
||||
[
|
||||
sg.Text("Smart Inversion Tracking System:", background_color='#242224'),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Enable:",
|
||||
default=self.config.gui_smartinversion_enabled,
|
||||
key=self.gui_smartinversion_enabled,
|
||||
background_color="#424042",
|
||||
tooltip="Enables Smart Inversion Tracking System",
|
||||
),
|
||||
|
||||
sg.Radio(
|
||||
"Use Left Eye",
|
||||
"smartinversion_selectedeye",
|
||||
background_color="#424042",
|
||||
tooltip="Uses the left eye as the tracked eye.",
|
||||
),
|
||||
|
||||
sg.Radio(
|
||||
"Use Right Eye",
|
||||
"smartinversion_selectedeye",
|
||||
default=self.config.gui_smartinversion_select_right,
|
||||
key=self.gui_smartinversion_select_right,
|
||||
background_color="#424042",
|
||||
tooltip="Uses the right eye as the tracked eye.",
|
||||
)
|
||||
],
|
||||
[
|
||||
sg.Text("Max. X-Axis Difference", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_smartinversion_thresh,
|
||||
key=self.gui_smartinversion_thresh,
|
||||
size=(0, 10),
|
||||
tooltip=(
|
||||
"Sets the maximum allowed difference in eye position (x-axis) to determine if the eyes are cross-eyed or not."
|
||||
"\n Lower value will make cross-eye detection more sensitive."
|
||||
)
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Inwards Look Threshold", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_smartinversion_minthresh,
|
||||
key=self.gui_smartinversion_minthresh,
|
||||
size=(0, 10),
|
||||
tooltip=(
|
||||
"Sets the minimum distance of looking in that's required before state can chaned to cross-eyed."
|
||||
"\n Lower value will make cross-eye detection more sensitive."
|
||||
)
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Inversion Trigger Frame Count", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_smartinversion_frame_count,
|
||||
key=self.gui_smartinversion_frame_count,
|
||||
size=(0, 10),
|
||||
tooltip=(
|
||||
"How long it takes to detect you are cross-eyed, or no longer cross-eyed."
|
||||
"\n Higher number means longer duration before changing in or out of being cross-eyed state."
|
||||
)
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Smoothing Decay Rate", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_smartinversion_smoothing_rate,
|
||||
key=self.gui_smartinversion_smoothing_rate,
|
||||
size=(0, 10),
|
||||
tooltip=(
|
||||
"How quickly eye smoothing decays when you enter or leave a cross-eyed state."
|
||||
"\nHigher number = shorter smoothing duration."
|
||||
)
|
||||
),
|
||||
],
|
||||
]
|
||||
91
EyeTrackApp/utils/smart_inversion.py
Normal file
91
EyeTrackApp/utils/smart_inversion.py
Normal file
@ -0,0 +1,91 @@
|
||||
from eye import EyeId
|
||||
from utils.misc_utils import clamp
|
||||
|
||||
def smart_inversion(self, var, out_x, out_y):
|
||||
|
||||
#Checks to see if the class already has frame counts, inversion attributes or smoothing attributes
|
||||
if not hasattr(self, "smartinversion_inverted_frame_count"):
|
||||
self.smartinversion_inverted_frame_count = 0
|
||||
if not hasattr(self, "smartinversion_normal_frame_count"):
|
||||
self.smartinversion_normal_frame_count = 0
|
||||
if not hasattr(self, "smartinversion_is_inverted"):
|
||||
self.smartinversion_is_inverted = False
|
||||
if not hasattr(self, "smartinversion_smoothing_progress"):
|
||||
self.smartinversion_smoothing_progress = 0
|
||||
if not hasattr(self, "smartinversion_smoothed_eye_x"):
|
||||
self.smartinversion_smoothed_eye_x = 0.0
|
||||
if not hasattr(self, "smartinversion_previous_inversion_state"):
|
||||
self.smartinversion_previous_inversion_state = False
|
||||
|
||||
#Updates eye positions with latest
|
||||
if self.eye_id == EyeId.LEFT:
|
||||
var.l_eye_x = out_x
|
||||
var.left_y = out_y
|
||||
|
||||
if self.eye_id == EyeId.RIGHT:
|
||||
var.r_eye_x = out_x
|
||||
var.right_y = out_y
|
||||
|
||||
#Checks if eyes are inverted, and then activates inversion if the conditions have been true for a specified number of frames.
|
||||
if (var.l_eye_x > 0 and var.r_eye_x < 0) and (abs(var.l_eye_x - var.r_eye_x) > self.settings.gui_smartinversion_thresh):
|
||||
self.smartinversion_inverted_frame_count = min(self.smartinversion_inverted_frame_count + 1, self.settings.gui_smartinversion_frame_count)
|
||||
|
||||
if self.smartinversion_inverted_frame_count == self.settings.gui_smartinversion_frame_count:
|
||||
if not self.smartinversion_is_inverted:
|
||||
self.smartinversion_is_inverted = True
|
||||
self.smartinversion_normal_frame_count = 0
|
||||
print(f"Inversion Activated")
|
||||
|
||||
#Checks if the eyes are no longer inverted, and then clears inversion if the conditions haven't been true for a specified number of frames.
|
||||
elif self.smartinversion_is_inverted and (
|
||||
not (var.l_eye_x > self.settings.gui_smartinversion_minthresh and var.r_eye_x < -self.settings.gui_smartinversion_minthresh) or
|
||||
abs(var.l_eye_x - var.r_eye_x) <= self.settings.gui_smartinversion_thresh
|
||||
):
|
||||
|
||||
self.smartinversion_normal_frame_count = min(self.smartinversion_normal_frame_count + 1, self.settings.gui_smartinversion_frame_count)
|
||||
|
||||
if self.smartinversion_normal_frame_count == self.settings.gui_smartinversion_frame_count:
|
||||
if self.smartinversion_is_inverted:
|
||||
self.smartinversion_is_inverted = False
|
||||
self.smartinversion_inverted_frame_count = 0
|
||||
print(f"Inversion Cleared")
|
||||
|
||||
#Checks if the inversion state has recently been toggled, and activates smoothing
|
||||
if self.smartinversion_previous_inversion_state != self.smartinversion_is_inverted:
|
||||
self.smartinversion_smoothing_progress = 1
|
||||
self.smartinversion_previous_inversion_state = self.smartinversion_is_inverted
|
||||
|
||||
#Determines which eye is being tracked based off selection and sets values accordingly
|
||||
if self.settings.gui_smartinversion_select_right:
|
||||
tracked_eye_x = var.r_eye_x
|
||||
tracked_eye_y = var.right_y
|
||||
recessive_eye = EyeId.LEFT
|
||||
dominant_eye = EyeId.RIGHT
|
||||
else:
|
||||
tracked_eye_x = var.l_eye_x
|
||||
tracked_eye_y = var.left_y
|
||||
recessive_eye = EyeId.RIGHT
|
||||
dominant_eye = EyeId.LEFT
|
||||
|
||||
out_x = tracked_eye_x
|
||||
out_y = tracked_eye_y
|
||||
|
||||
#Logic if smoothing is activated
|
||||
if self.smartinversion_smoothing_progress > 0:
|
||||
smartinversion_lerp_factor = (1 - self.smartinversion_smoothing_progress)
|
||||
|
||||
if self.smartinversion_is_inverted and self.eye_id == recessive_eye:
|
||||
self.smartinversion_smoothed_eye_x += (-tracked_eye_x - self.smartinversion_smoothed_eye_x) * smartinversion_lerp_factor
|
||||
else:
|
||||
self.smartinversion_smoothed_eye_x += (tracked_eye_x - self.smartinversion_smoothed_eye_x) * smartinversion_lerp_factor
|
||||
|
||||
self.smartinversion_smoothing_progress = max(self.smartinversion_smoothing_progress - self.settings.gui_smartinversion_smoothing_rate, 0)
|
||||
out_x = self.smartinversion_smoothed_eye_x
|
||||
|
||||
#Logic if inversion is active, but smoothing is not active
|
||||
elif self.smartinversion_is_inverted and self.eye_id == recessive_eye:
|
||||
out_x = -tracked_eye_x
|
||||
|
||||
out_y = tracked_eye_y
|
||||
|
||||
return out_x, out_y
|
||||
@ -80,6 +80,13 @@ def eyetrack_settings_config():
|
||||
gui_eyetune_maxout=1,
|
||||
gui_eyetune_maxup=1,
|
||||
gui_eyetune_maxdown=1,
|
||||
#Smart Inversion Tracking
|
||||
gui_smartinversion_enabled=False,
|
||||
gui_smartinversion_select_right=True,
|
||||
gui_smartinversion_thresh=0.4,
|
||||
gui_smartinversion_frame_count=10,
|
||||
gui_smartinversion_smoothing_rate=0.025,
|
||||
gui_smartinversion_minthresh=0.3,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user