From 8b676eaf41f5ec41870d96ed3b529c3c2ffb3bdf Mon Sep 17 00:00:00 2001 From: Assassinsorrow <49711232+ShyAssassin@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:28:25 +0200 Subject: [PATCH 1/2] Update to python 3.11 --- EyeTrackApp/camera.py | 7 - EyeTrackApp/config.py | 88 +-- EyeTrackApp/eye_processor.py | 3 +- EyeTrackApp/eyetrackapp.py | 13 +- EyeTrackApp/eyetrackapp.spec | 4 +- EyeTrackApp/osc.py | 18 +- .../pye3d.libs/.load-order-pye3d-0.3.0 | 1 - EyeTrackApp/pye3d.libs/vcruntime140_1.dll | Bin 37240 -> 0 bytes EyeTrackApp/pye3dcustom/__init__.py | 34 - EyeTrackApp/pye3dcustom/camera.py | 6 - EyeTrackApp/pye3dcustom/constants.py | 4 - EyeTrackApp/pye3dcustom/cpp/__init__.py | 0 .../cpp/projections.cp36-win_amd64.pyd | Bin 65536 -> 0 bytes .../cpp/pupil_detection_3d.cp36-win_amd64.pyd | Bin 163328 -> 0 bytes .../refraction_correction.cp36-win_amd64.pyd | Bin 152064 -> 0 bytes EyeTrackApp/pye3dcustom/detector_3d.py | 725 ------------------ EyeTrackApp/pye3dcustom/eye_model/__init__.py | 22 - EyeTrackApp/pye3dcustom/eye_model/abstract.py | 116 --- .../pye3dcustom/eye_model/asynchronous.py | 320 -------- .../eye_model/background_helper.py | 164 ---- EyeTrackApp/pye3dcustom/eye_model/base.py | 297 ------- EyeTrackApp/pye3dcustom/geometry/__init__.py | 0 .../pye3dcustom/geometry/intersections.py | 161 ---- .../pye3dcustom/geometry/primitives.py | 188 ----- .../pye3dcustom/geometry/projections.py | 123 --- EyeTrackApp/pye3dcustom/geometry/utilities.py | 92 --- EyeTrackApp/pye3dcustom/kalman.py | 58 -- EyeTrackApp/pye3dcustom/observation.py | 232 ------ EyeTrackApp/pye3dcustom/refraction.py | 141 ---- ...raction_model_gaze_vector_degree_3.msgpack | Bin 13522 -> 0 bytes ...action_model_pupil_circle_degree_3.msgpack | Bin 14602 -> 0 bytes ...t_refraction_model_radius_degree_3.msgpack | Bin 11362 -> 0 bytes ...ction_model_sphere_center_degree_3.msgpack | Bin 1726 -> 0 bytes EyeTrackApp/requirements.txt | 33 - poetry.lock | 575 +++++++------- pyproject.toml | 38 +- 36 files changed, 336 insertions(+), 3127 deletions(-) delete mode 100644 EyeTrackApp/pye3d.libs/.load-order-pye3d-0.3.0 delete mode 100644 EyeTrackApp/pye3d.libs/vcruntime140_1.dll delete mode 100644 EyeTrackApp/pye3dcustom/__init__.py delete mode 100644 EyeTrackApp/pye3dcustom/camera.py delete mode 100644 EyeTrackApp/pye3dcustom/constants.py delete mode 100644 EyeTrackApp/pye3dcustom/cpp/__init__.py delete mode 100644 EyeTrackApp/pye3dcustom/cpp/projections.cp36-win_amd64.pyd delete mode 100644 EyeTrackApp/pye3dcustom/cpp/pupil_detection_3d.cp36-win_amd64.pyd delete mode 100644 EyeTrackApp/pye3dcustom/cpp/refraction_correction.cp36-win_amd64.pyd delete mode 100644 EyeTrackApp/pye3dcustom/detector_3d.py delete mode 100644 EyeTrackApp/pye3dcustom/eye_model/__init__.py delete mode 100644 EyeTrackApp/pye3dcustom/eye_model/abstract.py delete mode 100644 EyeTrackApp/pye3dcustom/eye_model/asynchronous.py delete mode 100644 EyeTrackApp/pye3dcustom/eye_model/background_helper.py delete mode 100644 EyeTrackApp/pye3dcustom/eye_model/base.py delete mode 100644 EyeTrackApp/pye3dcustom/geometry/__init__.py delete mode 100644 EyeTrackApp/pye3dcustom/geometry/intersections.py delete mode 100644 EyeTrackApp/pye3dcustom/geometry/primitives.py delete mode 100644 EyeTrackApp/pye3dcustom/geometry/projections.py delete mode 100644 EyeTrackApp/pye3dcustom/geometry/utilities.py delete mode 100644 EyeTrackApp/pye3dcustom/kalman.py delete mode 100644 EyeTrackApp/pye3dcustom/observation.py delete mode 100644 EyeTrackApp/pye3dcustom/refraction.py delete mode 100644 EyeTrackApp/pye3dcustom/refraction_models/default_refraction_model_gaze_vector_degree_3.msgpack delete mode 100644 EyeTrackApp/pye3dcustom/refraction_models/default_refraction_model_pupil_circle_degree_3.msgpack delete mode 100644 EyeTrackApp/pye3dcustom/refraction_models/default_refraction_model_radius_degree_3.msgpack delete mode 100644 EyeTrackApp/pye3dcustom/refraction_models/default_refraction_model_sphere_center_degree_3.msgpack delete mode 100644 EyeTrackApp/requirements.txt diff --git a/EyeTrackApp/camera.py b/EyeTrackApp/camera.py index e4b2e21..86b7b0d 100644 --- a/EyeTrackApp/camera.py +++ b/EyeTrackApp/camera.py @@ -1,15 +1,8 @@ -from time import sleep - -import numpy - from config import EyeTrackConfig -import requests from enum import Enum import threading import queue -import runpy import cv2 -import time WAIT_TIME = 0.1 diff --git a/EyeTrackApp/config.py b/EyeTrackApp/config.py index 255e91f..3e5ea01 100644 --- a/EyeTrackApp/config.py +++ b/EyeTrackApp/config.py @@ -1,57 +1,48 @@ -from pickle import NONE -from dataclasses import dataclass from typing import Union, Dict -from dacite import from_dict, Config from osc import EyeId import os.path import json +from pydantic import BaseModel +CONFIG_FILE_NAME: str = "eyetrack_settings.json" -# TODO Who even needs synchronization? (We do.) - -@dataclass -class EyeTrackCameraConfig: - threshold: "int" = 0 - rotation_angle: "int" = 50 - roi_window_x: "int" = 0 - roi_window_y: "int" = 0 - roi_window_w: "int" = 0 - roi_window_h: "int" = 0 - focal_length: "int" = 30 - capture_source: "Union[int, str, None]" = None - gui_circular_crop: "bool" = False +class EyeTrackCameraConfig(BaseModel): + threshold: int = 0 + rotation_angle: int = 50 + roi_window_x: int = 0 + roi_window_y: int = 0 + roi_window_w: int = 0 + roi_window_h: int = 0 + focal_length: int = 30 + capture_source: Union[int, str, None] = None + gui_circular_crop: bool = False - - -@dataclass -class EyeTrackSettingsConfig: - gui_flip_x_axis_left: "bool" = False - gui_flip_x_axis_right: "bool" = False - gui_flip_y_axis: "bool" = False - gui_blob_fallback: "bool" = True - gui_min_cutoff: "str" = "0.0004" - gui_speed_coefficient: "str" = "0.9" - gui_osc_address: "str" = "127.0.0.1" - gui_osc_port: "str" = "9000" - gui_osc_receiver_port: "str" = "9001" - gui_osc_recenter_address: "str" = "/avatar/parameters/etvr_recenter" - gui_osc_recalibrate_address: "str" = "/avatar/parameters/etvr_recalibrate" - gui_blob_maxsize: "float" = 25 - gui_blob_minsize: "float" = 10 - gui_recenter_eyes: "bool" = False - gui_eye_falloff: "bool" = False - tracker_single_eye: "float" = 0 -CONFIG_FILE_NAME = "eyetrack_settings.json" +class EyeTrackSettingsConfig(BaseModel): + gui_flip_x_axis_left: bool = False + gui_flip_x_axis_right: bool = False + gui_flip_y_axis: bool = False + gui_blob_fallback: bool = True + gui_min_cutoff: str = "0.0004" + gui_speed_coefficient: str = "0.9" + gui_osc_address: str = "127.0.0.1" + gui_osc_port: str = "9000" + gui_osc_receiver_port: str = "9001" + gui_osc_recenter_address: str = "/avatar/parameters/etvr_recenter" + gui_osc_recalibrate_address: str = "/avatar/parameters/etvr_recalibrate" + gui_blob_maxsize: float = 25 + gui_blob_minsize: float = 10 + gui_recenter_eyes: bool = False + gui_eye_falloff: bool = False + tracker_single_eye: float = 0 -@dataclass -class EyeTrackConfig: - version: "int" = 1 +class EyeTrackConfig(BaseModel): + version: int = 1 right_eye: EyeTrackCameraConfig = EyeTrackCameraConfig() left_eye: EyeTrackCameraConfig = EyeTrackCameraConfig() settings: EyeTrackSettingsConfig = EyeTrackSettingsConfig() - eye_display_id: "EyeId" = EyeId.RIGHT + eye_display_id: EyeId = EyeId.RIGHT @staticmethod def load(): @@ -59,19 +50,8 @@ class EyeTrackConfig: print("No settings file, using base settings") return EyeTrackConfig() with open(CONFIG_FILE_NAME, "r") as settings_file: - # try: - config: EyeTrackConfig = from_dict( - data_class=EyeTrackConfig, data=json.load(settings_file), config=Config(type_hooks={EyeId: EyeId}) - ) - if config.version != EyeTrackConfig().version: - raise RuntimeError( - "Configuration does not contain version number, consider invalid" - ) - return config - # except: - # print("[INFO] Configuration invalid, creating new config") - # return EyeTrackConfig() + return EyeTrackConfig(**json.load(settings_file)) def save(self): with open(CONFIG_FILE_NAME, "w+") as settings_file: - json.dump(obj=self.__dict__, fp=settings_file, default=lambda x: x.__dict__) + json.dump(obj=self.dict(), fp=settings_file) diff --git a/EyeTrackApp/eye_processor.py b/EyeTrackApp/eye_processor.py index 51c9c89..88eaa5a 100644 --- a/EyeTrackApp/eye_processor.py +++ b/EyeTrackApp/eye_processor.py @@ -6,7 +6,8 @@ import asyncio sys.path.append(".") from config import EyeTrackCameraConfig from config import EyeTrackSettingsConfig -from pye3dcustom.detector_3d import CameraModel, Detector3D, DetectorMode +from pye3d.camera import CameraModel +from pye3d.detector_3d import Detector3D, DetectorMode import queue import threading import numpy as np diff --git a/EyeTrackApp/eyetrackapp.py b/EyeTrackApp/eyetrackapp.py index bb87c9c..c17565a 100644 --- a/EyeTrackApp/eyetrackapp.py +++ b/EyeTrackApp/eyetrackapp.py @@ -1,8 +1,4 @@ -# Random environment variable to speed up webcam opening on the MSMF backend. -# https://github.com/opencv/opencv/issues/17687 import os - -os.environ["OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS"] = "0" from osc import VRChatOSCReceiver, VRChatOSC, EyeId from config import EyeTrackConfig from camera_widget import CameraWidget @@ -10,6 +6,9 @@ from settings_widget import SettingsWidget import queue import threading import PySimpleGUI as sg +# Random environment variable to speed up webcam opening on the MSMF backend. +# https://github.com/opencv/opencv/issues/17687 +os.environ["OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS"] = "0" WINDOW_NAME = "EyeTrackApp" RIGHT_EYE_NAME = "-RIGHTEYEWIDGET-" @@ -35,7 +34,7 @@ def main(): # Check to see if we have an ROI. If not, bring up ROI finder GUI. # Spawn worker threads - osc_queue: "queue.Queue[tuple[bool, int, int]]" = queue.Queue() + osc_queue: queue.Queue[tuple[bool, int, int, int]] = queue.Queue() osc = VRChatOSC(cancellation_event, osc_queue, config) osc_thread = threading.Thread(target=osc.run) # start worker threads @@ -108,7 +107,6 @@ def main(): if config.eye_display_id in [EyeId.LEFT, EyeId.BOTH]: eyes[1].start() - eyes[0].ransac.calibration_frame_counter if config.eye_display_id in [EyeId.RIGHT, EyeId.BOTH]: eyes[0].start() @@ -130,7 +128,6 @@ def main(): # If we're in either mode and someone hits q, quit immediately if event == "Exit" or event == sg.WIN_CLOSED: - # eyes[2].stop() for eye in eyes: eye.stop() cancellation_event.set() @@ -138,7 +135,7 @@ def main(): osc_thread.join() # TODO: find a way to have this function run on join maybe?? # threading.Event() wont work because pythonosc spawns its own thread. - # only way i can see to get around this is an ugly while loop that only checks if a threading event is trigggered + # only way i can see to get around this is an ugly while loop that only checks if a threading event is triggered # and then call the pythonosc shutdown function osc_receiver.shutdown() osc_receiver_thread.join() diff --git a/EyeTrackApp/eyetrackapp.spec b/EyeTrackApp/eyetrackapp.spec index 1bd3184..0939df4 100644 --- a/EyeTrackApp/eyetrackapp.spec +++ b/EyeTrackApp/eyetrackapp.spec @@ -5,8 +5,8 @@ block_cipher = None a = Analysis(['eyetrackapp.py'], pathex=[], - binaries=[("pye3d.libs/*", "pye3d.libs"), ("pye3d.libs/.*", "pye3d.libs")], - datas=[("pye3dcustom/refraction_models/*", "pye3dcustom/refraction_models"), ("Audio/*", "Audio"), ("Images/*", "Images/")], + binaries=[], + datas=[("Audio/*", "Audio"), ("Images/*", "Images/")], hiddenimports=['cv2', 'numpy', 'PySimpleGui'], hookspath=[], hooksconfig={}, diff --git a/EyeTrackApp/osc.py b/EyeTrackApp/osc.py index bf4cd70..51c7862 100644 --- a/EyeTrackApp/osc.py +++ b/EyeTrackApp/osc.py @@ -17,7 +17,7 @@ from config import EyeTrackConfig class VRChatOSC: # Use a tuple of blink (true, blinking, false, not), x, y for now. Probably clearer as a class but # we're stuck in python 3.6 so still no dataclasses. God I hate python. - def __init__(self, cancellation_event: "threading.Event", msg_queue: "queue.Queue[tuple[bool, int, int, int]]", main_config: EyeTrackConfig,): + def __init__(self, cancellation_event: threading.Event, msg_queue: queue.Queue[tuple[bool, int, int]], main_config: EyeTrackConfig,): self.main_config = main_config self.config = main_config.settings self.client = udp_client.SimpleUDPClient(self.config.gui_osc_address, int(self.config.gui_osc_port)) # use OSC port and address that was set in the config @@ -63,9 +63,7 @@ class VRChatOSC: self.client.send_message("/avatar/parameters/RightEyeX", eye_info.x) self.client.send_message("/avatar/parameters/RightEyeLid", float(0))# old param open right self.client.send_message("/avatar/parameters/RightEyeLidExpandedSqueeze", float(0.8)) # open right eye - # self.client.send_message( - # "/avatar/parameters/EyesDilation", eye_info.pupil_dialation - #) + if eye_id in [EyeId.LEFT]: yl = eye_info.y sx = eye_info.x @@ -79,7 +77,7 @@ class VRChatOSC: y = (yr + yl) / 2 self.client.send_message("/avatar/parameters/EyesY", y) else: - if self.config.gui_eye_falloff == True: + if self.config.gui_eye_falloff: if eye_id in [EyeId.LEFT]: lb = True if eye_id in [EyeId.RIGHT]: @@ -102,7 +100,6 @@ class VRChatOSC: last_blink = time.time() else: if self.config.tracker_single_eye == 1 or self.config.tracker_single_eye == 2: - if last_blink > 0.5: for i in range(4): self.client.send_message("/avatar/parameters/RightEyeLid", float(1)) #close eye @@ -127,12 +124,13 @@ class VRChatOSC: self.client.send_message("/avatar/parameters/RightEyeLidExpandedSqueeze", float(0)) # close eye last_blink = time.time() + class VRChatOSCReceiver: - def __init__(self, cancellation_event: "threading.Event", main_config: EyeTrackConfig, eyes: []): + def __init__(self, cancellation_event: threading.Event, main_config: EyeTrackConfig, eyes: []): self.config = main_config.settings self.cancellation_event = cancellation_event self.dispatcher = dispatcher.Dispatcher() - self.eyes = eyes # we cant import CameraWidget so any type it is + self.eyes = eyes # we cant import CameraWidget so any type it is self.server = osc_server.OSCUDPServer((self.config.gui_osc_address, int(self.config.gui_osc_receiver_port)), self.dispatcher) def shutdown(self): @@ -140,13 +138,13 @@ class VRChatOSCReceiver: self.server.shutdown() def recenter_eyes(self, address, osc_value): - if type(osc_value) != bool: return # just incase we get anything other than bool + if type(osc_value) != bool: return # just incase we get anything other than bool if osc_value: for eye in self.eyes: eye.settings.gui_recenter_eyes = True def recalibrate_eyes(self, address, osc_value): - if type(osc_value) != bool: return # just incase we get anything other than bool + if type(osc_value) != bool: return # just incase we get anything other than bool if osc_value: for eye in self.eyes: eye.ransac.calibration_frame_counter = 300 diff --git a/EyeTrackApp/pye3d.libs/.load-order-pye3d-0.3.0 b/EyeTrackApp/pye3d.libs/.load-order-pye3d-0.3.0 deleted file mode 100644 index 7f0e4c2..0000000 --- a/EyeTrackApp/pye3d.libs/.load-order-pye3d-0.3.0 +++ /dev/null @@ -1 +0,0 @@ -vcruntime140_1.dll diff --git a/EyeTrackApp/pye3d.libs/vcruntime140_1.dll b/EyeTrackApp/pye3d.libs/vcruntime140_1.dll deleted file mode 100644 index e54826265da849ac458655bd5b03564ea5f5827d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37240 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 diff --git a/EyeTrackApp/pye3dcustom/__init__.py b/EyeTrackApp/pye3dcustom/__init__.py deleted file mode 100644 index 3393cbc..0000000 --- a/EyeTrackApp/pye3dcustom/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ - - -"""""" # start delvewheel patch -def _delvewheel_init_patch_0_0_15(): - import os - import sys - libs_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'pye3d.libs')) - if sys.version_info[:2] >= (3, 8): - if os.path.exists(os.path.join(sys.base_prefix, 'conda-meta')): - # backup the state of the environment variable CONDA_DLL_SEARCH_MODIFICATION_ENABLE - conda_dll_search_modification_enable = os.environ.get("CONDA_DLL_SEARCH_MODIFICATION_ENABLE") - os.environ['CONDA_DLL_SEARCH_MODIFICATION_ENABLE']='1' - - os.add_dll_directory(libs_dir) - - if os.path.exists(os.path.join(sys.base_prefix, 'conda-meta')): - # restore the state of the environment variable CONDA_DLL_SEARCH_MODIFICATION_ENABLE - if conda_dll_search_modification_enable is None: - os.environ.pop("CONDA_DLL_SEARCH_MODIFICATION_ENABLE", None) - else: - os.environ["CONDA_DLL_SEARCH_MODIFICATION_ENABLE"] = conda_dll_search_modification_enable - else: - from ctypes import WinDLL - with open(os.path.join(libs_dir, '.load-order-pye3d-0.3.0')) as file: - load_order = file.read().split() - for lib in load_order: - WinDLL(os.path.join(libs_dir, lib)) - - -_delvewheel_init_patch_0_0_15() -del _delvewheel_init_patch_0_0_15 -# end delvewheel patch - -__version__ = "0.3.0" diff --git a/EyeTrackApp/pye3dcustom/camera.py b/EyeTrackApp/pye3dcustom/camera.py deleted file mode 100644 index b4cc8c4..0000000 --- a/EyeTrackApp/pye3dcustom/camera.py +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Tuple, NamedTuple - - -class CameraModel(NamedTuple): - focal_length: float - resolution: Tuple[float, float] diff --git a/EyeTrackApp/pye3dcustom/constants.py b/EyeTrackApp/pye3dcustom/constants.py deleted file mode 100644 index fbe5ed4..0000000 --- a/EyeTrackApp/pye3dcustom/constants.py +++ /dev/null @@ -1,4 +0,0 @@ -import typing as T - -_EYE_RADIUS_DEFAULT: float = 10.392304845413264 -DEFAULT_SPHERE_CENTER: T.Tuple[float, float, float] = (0.0, 0.0, 35.0) diff --git a/EyeTrackApp/pye3dcustom/cpp/__init__.py b/EyeTrackApp/pye3dcustom/cpp/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/EyeTrackApp/pye3dcustom/cpp/projections.cp36-win_amd64.pyd b/EyeTrackApp/pye3dcustom/cpp/projections.cp36-win_amd64.pyd deleted file mode 100644 index 55a1fd8627c1c447deee7c1dfc13a2cdbe29cded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 OgHH5HFM4Bk@c#l5JrrvI diff --git a/EyeTrackApp/pye3dcustom/cpp/pupil_detection_3d.cp36-win_amd64.pyd b/EyeTrackApp/pye3dcustom/cpp/pupil_detection_3d.cp36-win_amd64.pyd deleted file mode 100644 index dbaffc6bb93a4b9001f61a964a9e1565c01d56dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163328 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%0DiW*4T9KuNeMs0u#SI5%vWo0q&~ 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 diff --git a/EyeTrackApp/pye3dcustom/detector_3d.py b/EyeTrackApp/pye3dcustom/detector_3d.py deleted file mode 100644 index fa95696..0000000 --- a/EyeTrackApp/pye3dcustom/detector_3d.py +++ /dev/null @@ -1,725 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import enum -import logging -import traceback -from typing import Dict, NamedTuple, Type - -import numpy as np -import cv2 # Todo: DELETE -from .geometry.projections import ( - unproject_edges_to_sphere, - project_point_into_image_plane, -) # Todo: DELETE - -from .camera import CameraModel -from .constants import _EYE_RADIUS_DEFAULT -from .cpp.pupil_detection_3d import get_edges -from .cpp.pupil_detection_3d import search_on_sphere as search_on_sphere -from .geometry.primitives import Circle, Ellipse, Sphere -from .geometry.projections import ( - project_circle_into_image_plane, - project_sphere_into_image_plane, -) -from .geometry.utilities import cart2sph, sph2cart -from .kalman import KalmanFilter -from .observation import ( - BinBufferedObservationStorage, - BufferedObservationStorage, - Observation, -) -from .eye_model import ( - SphereCenterEstimates, - TwoSphereModelAbstract, - TwoSphereModel, - TwoSphereModelAsync, -) - -logger = logging.getLogger(__name__) - - -class DetectorMode(enum.Enum): - blocking = TwoSphereModel - asynchronous = TwoSphereModelAsync - - @classmethod - def from_name(cls, mode_name: str): - return {mode.name: mode for mode in cls}[mode_name] - - -def ellipse2dict(ellipse: Ellipse) -> Dict: - return { - "center": ( - ellipse.center[0], - ellipse.center[1], - ), - "axes": ( - ellipse.minor_radius, - ellipse.major_radius, - ), - "angle": ellipse.angle, - } - - -def circle2dict(circle: Circle) -> Dict: - return { - "center": ( - circle.center[0], - circle.center[1], - circle.center[2], - ), - "normal": ( - circle.normal[0], - circle.normal[1], - circle.normal[2], - ), - "radius": float(circle.radius), - } - - -class Prediction(NamedTuple): - sphere_center: np.ndarray - pupil_circle: Circle - - -class Search3DResult(NamedTuple): - circle: Circle - confidence: float - - -def sigmoid(x, baseline=0.1, amplitude=500.0, center=0.99, width=0.02): - return baseline + amplitude * 1.0 / (1.0 + np.exp(-(x - center) / width)) - - -class Detector3D(object): - def __init__( - self, - camera: CameraModel, - threshold_swirski=0.7, - threshold_kalman=0.98, - threshold_short_term=0.8, - threshold_long_term=0.98, - long_term_buffer_size=30, - long_term_forget_time=5, - long_term_forget_observations=300, - long_term_mode: DetectorMode = DetectorMode.blocking, - model_update_interval_long_term=1.0, - model_update_interval_ult_long_term=10.0, - model_warmup_duration=5.0, - calculate_rms_residual=False, - ): - self._camera = camera - self._long_term_mode = long_term_mode - self._calculate_rms_residual = calculate_rms_residual - # NOTE: changing settings after intialization can lead to inconsistent behavior - # if .reset() is not called. - self._settings = { - "threshold_swirski": threshold_swirski, - "threshold_kalman": threshold_kalman, - "threshold_short_term": threshold_short_term, - "threshold_long_term": threshold_long_term, - "long_term_buffer_size": long_term_buffer_size, - "long_term_forget_time": long_term_forget_time, - "long_term_forget_observations": long_term_forget_observations, - "model_update_interval_long_term": model_update_interval_long_term, - "model_update_interval_ult_long_term": model_update_interval_ult_long_term, - "model_warmup_duration": model_warmup_duration, - } - self.reset() - logger.debug( - f"{type(self)} initialized with " - f"long_term_mode={long_term_mode} " - f"calculate_rms_residual={calculate_rms_residual} " - f"settings={self._settings}" - ) - - @property - def camera(self) -> CameraModel: - return self._camera - - @property - def long_term_mode(self) -> DetectorMode: - return self._long_term_mode - - @long_term_mode.setter - def long_term_mode(self, mode: DetectorMode): - needs_reset = mode != self._long_term_mode - self._long_term_mode = mode - if needs_reset: - self.reset() - - @property - def is_long_term_model_frozen(self) -> bool: - # If _ult_long_term_schedule is paused or not does not actually matter. The - # _ult_long_term_model is only used for fitting the _long_term_model. If the - # _long_term_schedule is paused, the _long_term_model is not being fitted and - # therefore the state of _ult_long_term_model will be ignored. - return self._long_term_schedule.is_paused - - @is_long_term_model_frozen.setter - def is_long_term_model_frozen(self, should_be_frozen: bool) -> None: - # We pause/resume _ult_long_term_schedule here as well to save CPU resources - # while the _long_term_model is frozen. - if should_be_frozen: - self._long_term_schedule.pause() - self._ult_long_term_schedule.pause() - else: - self._long_term_schedule.resume() - self._ult_long_term_schedule.resume() - - def reset_camera(self, camera: CameraModel): - """Change camera model and reset detector state.""" - self._camera = camera - self.reset() - - def reset(self): - self._cleanup_models() - self._initialize_models( - long_term_model_cls=self._long_term_mode.value, - ultra_long_term_model_cls=self._long_term_mode.value, - ) - self._long_term_schedule = _ModelUpdateSchedule( - update_interval=self._settings["model_update_interval_long_term"], - warmup_duration=self._settings["model_warmup_duration"], - ) - self._ult_long_term_schedule = _ModelUpdateSchedule( - update_interval=self._settings["model_update_interval_ult_long_term"], - warmup_duration=self._settings["model_warmup_duration"], - ) - - self.kalman_filter = KalmanFilter() - - def _initialize_models( - self, - short_term_model_cls: Type[TwoSphereModelAbstract] = TwoSphereModel, - long_term_model_cls: Type[TwoSphereModelAbstract] = TwoSphereModel, - ultra_long_term_model_cls: Type[TwoSphereModelAbstract] = TwoSphereModel, - ): - # Recreate all models. This is required in case any of the settings (incl - # camera) changed in the meantime. - self.short_term_model = short_term_model_cls( - camera=self.camera, - storage_cls=BufferedObservationStorage, - storage_kwargs=dict( - confidence_threshold=self._settings["threshold_short_term"], - buffer_length=10, - ), - ) - self.long_term_model = long_term_model_cls( - camera=self.camera, - storage_cls=BinBufferedObservationStorage, - storage_kwargs=dict( - camera=self.camera, - confidence_threshold=self._settings["threshold_long_term"], - n_bins_horizontal=10, - bin_buffer_length=self._settings["long_term_buffer_size"], - forget_min_observations=self._settings["long_term_forget_observations"], - forget_min_time=self._settings["long_term_forget_time"], - ), - ) - self.ultra_long_term_model = ultra_long_term_model_cls( - camera=self.camera, - storage_cls=BinBufferedObservationStorage, - storage_kwargs=dict( - camera=self.camera, - confidence_threshold=self._settings["threshold_long_term"], - n_bins_horizontal=10, - bin_buffer_length=self._settings["long_term_buffer_size"], - forget_min_observations=( - 2 * self._settings["long_term_forget_observations"] - ), - forget_min_time=60, - ), - ) - - def _cleanup_models(self): - try: - self.short_term_model.cleanup() - self.long_term_model.cleanup() - self.ultra_long_term_model.cleanup() - except AttributeError: - pass # models have not been initialized yet - - def update_and_detect( - self, - pupil_datum: Dict, - frame: np.ndarray, - apply_refraction_correction: bool = True, - debug: bool = False, - ): - # update models - observation = self._extract_observation(pupil_datum) - self.update_models(observation) - - # predict target variables - sphere_center = self.long_term_model.sphere_center - pupil_circle = self._predict_pupil_circle(observation, frame) - prediction_uncorrected = Prediction(sphere_center, pupil_circle) - - # apply refraction correction - if apply_refraction_correction: - pupil_circle = self.long_term_model.apply_refraction_correction( - pupil_circle - ) - sphere_center = self.long_term_model.corrected_sphere_center - # Falls back to uncorrected version if correction is disabled - prediction_corrected = Prediction(sphere_center, pupil_circle) - - result = self._prepare_result( - observation, - prediction_uncorrected=prediction_uncorrected, - prediction_corrected=prediction_corrected, - ) - - if debug: - result["debug_info"] = self._collect_debug_info() - - return result - - def update_models(self, observation: Observation): - self.short_term_model.add_observation(observation) - self.long_term_model.add_observation(observation) - self.ultra_long_term_model.add_observation(observation) - - if ( - self.short_term_model.n_observations <= 0 - or self.long_term_model.n_observations <= 0 - or self.ultra_long_term_model.n_observations <= 0 - ): - return - - try: - if self._ult_long_term_schedule.is_update_due(observation.timestamp): - self.ultra_long_term_model.estimate_sphere_center( - calculate_rms_residual=self._calculate_rms_residual - ) - - if self._long_term_schedule.is_update_due(observation.timestamp): - # update long term model with ultra long term bias - long_term_estimate = self.long_term_model.estimate_sphere_center( - prior_3d=self.ultra_long_term_model.sphere_center, - prior_strength=0.1, - calculate_rms_residual=self._calculate_rms_residual, - ) - else: - # use existing sphere center estimates - long_term_estimate = SphereCenterEstimates( - projected=self.long_term_model.projected_sphere_center, - three_dim=self.long_term_model.sphere_center, - rms_residual=self.long_term_model.rms_residual, - ) - - # update short term model with help of long-term model - # using 2d center for disambiguation and 3d center as prior bias - # prior strength is set as a funcition of circularity of the 2D pupil - # when frozen: do not update - if not self.is_long_term_model_frozen: - circularity_mean = self.short_term_model.mean_observation_circularity() - self.short_term_model.estimate_sphere_center( - from_2d=long_term_estimate.projected, - prior_3d=long_term_estimate.three_dim, - prior_strength=sigmoid(circularity_mean), - calculate_rms_residual=self._calculate_rms_residual, - ) - except Exception: - # Known issues: - # - Can raise numpy.linalg.LinAlgError: SVD did not converge - logger.error("Error updating models:") - logger.debug(traceback.format_exc()) - - def _extract_observation(self, pupil_datum: Dict) -> Observation: - width, height = self.camera.resolution - center = ( - pupil_datum["ellipse"]["center"][0] - width / 2, - pupil_datum["ellipse"]["center"][1] - height / 2, - ) - minor_radius = pupil_datum["ellipse"]["axes"][0] / 2.0 - major_radius = pupil_datum["ellipse"]["axes"][1] / 2.0 - angle = (pupil_datum["ellipse"]["angle"] - 90.0) * np.pi / 180.0 - ellipse = Ellipse(center, minor_radius, major_radius, angle) - - return Observation( - ellipse, - pupil_datum["confidence"], - pupil_datum["timestamp"], - self.camera.focal_length, - ) - - def _predict_pupil_circle( - self, observation: Observation, frame: np.ndarray - ) -> Circle: - # NOTE: General idea: predict pupil circle from long and short term models based - # on current observation. Filter results with a kalman filter. - - # Kalman filter needs to be queried every timestamp to update it internally. - pupil_circle_kalman = self._predict_from_kalman_filter(observation.timestamp) - - if observation.confidence > self._settings["threshold_swirski"]: - # high-confidence observation, use to construct pupil circle from models - - # short-term-model is best for estimating gaze direction (circle normal) if - # one needs to assume slippage. long-term-model ist more stable for - # positions (center and radius) - long_term = self.long_term_model.predict_pupil_circle(observation) - if self.is_long_term_model_frozen: - normal = long_term.normal - else: - short_term = self.short_term_model.predict_pupil_circle(observation) - normal = short_term.normal - pupil_circle = Circle( - normal=normal, - center=long_term.center, - radius=long_term.radius, - ) - - else: - # low confidence: use kalman prediction to search for circles in image - pupil_circle, confidence_3d_search = self._predict_from_3d_search( - frame, best_guess=pupil_circle_kalman - ) - observation.confidence = confidence_3d_search - - if observation.confidence > self._settings["threshold_kalman"]: - # very-high-confidence: correct kalman filter - self._correct_kalman_filter(pupil_circle) - - return pupil_circle - - def _predict_from_kalman_filter(self, timestamp): - phi, theta, pupil_radius_kalman = self.kalman_filter.predict(timestamp) - gaze_vector_kalman = sph2cart(phi, theta) - pupil_center_kalman = ( - self.short_term_model.sphere_center - + _EYE_RADIUS_DEFAULT * gaze_vector_kalman - ) - pupil_circle_kalman = Circle( - pupil_center_kalman, gaze_vector_kalman, pupil_radius_kalman - ) - return pupil_circle_kalman - - def _correct_kalman_filter(self, observed_pupil_circle: Circle): - if observed_pupil_circle.is_null(): - return - - phi, theta, r = observed_pupil_circle.spherical_representation() - self.kalman_filter.correct(phi, theta, r) - - def _predict_from_3d_search( - # TODO: Remove debug code - self, - frame: np.ndarray, - best_guess: Circle, - debug=False, - ) -> Search3DResult: - no_result = Search3DResult(Circle.null(), 0.0) - - if best_guess.is_null(): - return no_result - - frame, frame_roi, edge_frame, edges, roi = get_edges( - frame, - best_guess.normal, - best_guess.radius, - self.long_term_model.sphere_center, - _EYE_RADIUS_DEFAULT, - self.camera.focal_length, - self.camera.resolution, - major_axis_factor=2.5, - ) - - if len(edges) <= 0: - return no_result - - (gaze_vector, pupil_radius, final_edges, edges_on_sphere) = search_on_sphere( - edges, - best_guess.normal, - best_guess.radius, - self.long_term_model.sphere_center, - _EYE_RADIUS_DEFAULT, - self.camera.focal_length, - self.camera.resolution, - ) - - if debug: - frame_ = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR) - try: - for edge in edges_on_sphere: - edge = project_point_into_image_plane( - edge, self.camera.focal_length - ).astype(np.int) - edge[0] += self.camera.resolution[0] / 2 - edge[1] += self.camera.resolution[1] / 2 - cv2.rectangle( - frame_, - (edge[0] - roi[2], edge[1] - roi[0]), - (edge[0] + 1 - roi[2], edge[1] + 1 - roi[0]), - (255, 0, 0), - 2, - ) - - for edge in final_edges: - edge = project_point_into_image_plane( - edge, self.camera.focal_length - ).astype(np.int) - edge[0] += self.camera.resolution[0] / 2 - edge[1] += self.camera.resolution[1] / 2 - cv2.rectangle( - frame_, - (edge[0] - roi[2], edge[1] - roi[0]), - (edge[0] + 1 - roi[2], edge[1] + 1 - roi[0]), - (255, 255, 255), - 1, - ) - - cv2.imshow("", frame_) - cv2.waitKey(1) - except Exception as e: - print(e) - - pupil_center = ( - self.long_term_model.sphere_center + _EYE_RADIUS_DEFAULT * gaze_vector - ) - pupil_circle = Circle(pupil_center, gaze_vector, pupil_radius) - - if pupil_circle.is_null(): - confidence_3d_search = 0.0 - else: - ellipse_2d = project_circle_into_image_plane( - pupil_circle, - focal_length=self.camera.focal_length, - transform=False, - width=self.camera.resolution[0], - height=self.camera.resolution[1], - ) - if ellipse_2d: - circumference = ellipse_2d.circumference() - confidence_3d_search = np.clip( - len(final_edges) / circumference, 0.0, 1.0 - ) - else: - confidence_3d_search = 0.0 - - return Search3DResult(pupil_circle, confidence_3d_search * 0.6) - - def _prepare_result( - self, - observation: Observation, - prediction_uncorrected: Prediction, - prediction_corrected: Prediction, - ) -> Dict: - """[summary] - - Args: - observation (Observation): [description] - prediction_uncorrected (Prediction): Used for 2d projections - prediction_corrected (Prediction): Used for 3d data - - Returns: - Dict: pye3d pupil detection result - """ - - result = { - "timestamp": observation.timestamp, - "sphere": { - "center": ( - prediction_corrected.sphere_center[0], - prediction_corrected.sphere_center[1], - prediction_corrected.sphere_center[2], - ), - "radius": _EYE_RADIUS_DEFAULT, - }, - } - - eye_sphere_projected = project_sphere_into_image_plane( - Sphere(prediction_uncorrected.sphere_center, _EYE_RADIUS_DEFAULT), - transform=True, - focal_length=self.camera.focal_length, - width=self.camera.resolution[0], - height=self.camera.resolution[1], - ) - result["projected_sphere"] = ellipse2dict(eye_sphere_projected) - - result["circle_3d"] = circle2dict(prediction_corrected.pupil_circle) - - result["diameter_3d"] = prediction_corrected.pupil_circle.radius * 2 - - projected_pupil_circle = project_circle_into_image_plane( - prediction_uncorrected.pupil_circle, - focal_length=self.camera.focal_length, - transform=True, - width=self.camera.resolution[0], - height=self.camera.resolution[1], - ) - if not projected_pupil_circle: - projected_pupil_circle = Ellipse(np.asarray([0.0, 0.0]), 0.0, 0.0, 0.0) - - result["ellipse"] = ellipse2dict(projected_pupil_circle) - result["location"] = result["ellipse"]["center"] # pupil center in pixels - - # projected_pupil_circle is an OpenCV ellipse, i.e. major_radius is major diameter - result["diameter"] = projected_pupil_circle.major_radius - - result["confidence"] = observation.confidence - - # Model confidence: - # - Prior to version 0.1.0, model_confidence was fixed to 1.0 as there was no - # way to estimate it - # - Starting with version 0.1.0, model_confidence is 1.0 by default but set to - # 0.1 if at least one model output exceeds its physiologically reasonable - # range. These ranges also inform the input range for the refraction - # correction function. - # If the ranges are exceeded, it is likely that the model is either not fit - # well or the 2d input ellipse was a false detection. - model_confidence_default = 1.0 - model_confidence_out_of_range = 0.1 - model_confidence_phi_theta_nan = 0.0 - - result["model_confidence"] = model_confidence_default - - phi, theta = cart2sph(prediction_corrected.pupil_circle.normal) - if not np.any(np.isnan([phi, theta])): - result["theta"] = theta - result["phi"] = phi - - is_phi_in_range = -80 <= np.rad2deg(phi) + 90.0 <= 80 - is_theta_in_range = -80 <= np.rad2deg(theta) - 90.0 <= 80 - if not is_phi_in_range or not is_theta_in_range: - result["model_confidence"] = model_confidence_out_of_range - else: - result["theta"] = 0.0 - result["phi"] = 0.0 - result["model_confidence"] = model_confidence_phi_theta_nan - - is_center_x_in_range = -10 <= prediction_corrected.sphere_center[0] <= 10 - is_center_y_in_range = -10 <= prediction_corrected.sphere_center[1] <= 10 - is_center_z_in_range = 20 <= prediction_corrected.sphere_center[2] <= 75 - is_diameter_in_range = 1.0 <= result["diameter_3d"] <= 9.0 - parameters_in_range = ( - is_center_x_in_range, - is_center_y_in_range, - is_center_z_in_range, - is_diameter_in_range, - ) - if not all(parameters_in_range): - result["model_confidence"] = model_confidence_out_of_range - - return result - - def _collect_debug_info(self): - debug_info = {} - - projected_short_term = project_sphere_into_image_plane( - Sphere(self.short_term_model.sphere_center, _EYE_RADIUS_DEFAULT), - transform=True, - focal_length=self.camera.focal_length, - width=self.camera.resolution[0], - height=self.camera.resolution[1], - ) - projected_long_term = project_sphere_into_image_plane( - Sphere(self.long_term_model.sphere_center, _EYE_RADIUS_DEFAULT), - transform=True, - focal_length=self.camera.focal_length, - width=self.camera.resolution[0], - height=self.camera.resolution[1], - ) - projected_ultra_long_term = project_sphere_into_image_plane( - Sphere(self.ultra_long_term_model.sphere_center, _EYE_RADIUS_DEFAULT), - transform=True, - focal_length=self.camera.focal_length, - width=self.camera.resolution[0], - height=self.camera.resolution[1], - ) - debug_info["projected_short_term"] = ellipse2dict(projected_short_term) - debug_info["projected_long_term"] = ellipse2dict(projected_long_term) - debug_info["projected_ultra_long_term"] = ellipse2dict( - projected_ultra_long_term - ) - - try: - bin_data = self.long_term_model.storage.get_bin_counts() - max_bin_level = np.max(bin_data) - if max_bin_level >= 0: - bin_data = bin_data / max_bin_level - bin_data = np.flip(bin_data, axis=0) - debug_info["bin_data"] = bin_data.tolist() - except AttributeError: - debug_info["bin_data"] = [] - - # TODO: Pupil visualizer_pye3d.py attempts to draw Dierkes lines. Currently we - # don't calculate them here, we could probably do that again. Based on which - # model? Might be hard to do when things run in the background. We might have to - # remove this from the visualizer_pye3d.py - debug_info["Dierkes_lines"] = [] - - return debug_info - - # pupil-detector interface: See base class implementation as reference: - # https://github.com/pupil-labs/pupil-detectors/blob/master/src/pupil_detectors/detector_base.pyx - - PUBLIC_PROPERTY_NAMES = ("is_long_term_model_frozen",) - - def get_properties(self): - return { - property_name: getattr(self, property_name) - for property_name in self.PUBLIC_PROPERTY_NAMES - if hasattr(self, property_name) - } - - def update_properties(self, properties): - keys_to_update = set(self.PUBLIC_PROPERTY_NAMES) - keys_to_update.intersection_update(properties.keys()) - for key in keys_to_update: - expected_type = type(getattr(self, key)) - value = properties[key] - try: - value = expected_type(value) - except ValueError as e: - raise ValueError( - f"Value `{repr(value)}` for key `{key}` could not be converted to" - f" expected type: {expected_type}" - ) from e - setattr(self, key, value) - - -class _ModelUpdateSchedule: - def __init__(self, update_interval: float, warmup_duration: float = 5.0) -> None: - self._update_interval = update_interval - self._warmup_duration = warmup_duration - self._warmup_start = None - self._paused = False - self._last_update = None - - @property - def is_paused(self) -> bool: - return self._paused - - def pause(self) -> None: - self._paused = True - - def resume(self) -> None: - self._paused = False - self._last_update = None - - def is_update_due(self, current_time: float): - if self._paused: - return False - if self._warmup_start is None: - self._warmup_start = current_time - return True - if current_time - self._warmup_start < self._warmup_duration: - return True - if self._last_update is None: - self._last_update = current_time - return True - if current_time - self._last_update > self._update_interval: - self._last_update = current_time - return True - return False diff --git a/EyeTrackApp/pye3dcustom/eye_model/__init__.py b/EyeTrackApp/pye3dcustom/eye_model/__init__.py deleted file mode 100644 index aab712a..0000000 --- a/EyeTrackApp/pye3dcustom/eye_model/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" - -from .abstract import TwoSphereModelAbstract, SphereCenterEstimates -from .base import TwoSphereModel -from .asynchronous import TwoSphereModelAsync - - -__all__ = [ - "TwoSphereModelAbstract", - "TwoSphereModel", - "TwoSphereModelAsync", - "SphereCenterEstimates", -] diff --git a/EyeTrackApp/pye3dcustom/eye_model/abstract.py b/EyeTrackApp/pye3dcustom/eye_model/abstract.py deleted file mode 100644 index 7ed88f5..0000000 --- a/EyeTrackApp/pye3dcustom/eye_model/abstract.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import abc -import typing as T - -import numpy as np - -from ..geometry.primitives import Circle -from ..observation import Observation, ObservationStorage -from ..camera import CameraModel - - -class SphereCenterEstimates(T.NamedTuple): - projected: np.ndarray - three_dim: np.ndarray - rms_residual: T.Optional[float] = None - - -class TwoSphereModelAbstract(abc.ABC): - @abc.abstractmethod - def __init__( - self, - camera: CameraModel, - storage_cls: T.Type[ObservationStorage] = None, - storage_kwargs: T.Dict = None, - ): - raise NotImplementedError - - @abc.abstractmethod - def add_observation(self, observation: Observation): - raise NotImplementedError - - @property - @abc.abstractmethod - def n_observations(self) -> int: - raise NotImplementedError - - @property - @abc.abstractmethod - def sphere_center(self) -> np.ndarray: - raise NotImplementedError - - @property - @abc.abstractmethod - def corrected_sphere_center(self) -> np.ndarray: - raise NotImplementedError - - @property - @abc.abstractmethod - def projected_sphere_center(self) -> np.ndarray: - raise NotImplementedError - - @abc.abstractmethod - def set_sphere_center(self, new_sphere_center: np.ndarray): - raise NotImplementedError - - @abc.abstractmethod - def estimate_sphere_center( - self, - from_2d: T.Optional[np.ndarray] = None, - prior_3d: T.Optional[np.ndarray] = None, - prior_strength: float = 0.0, - calculate_rms_residual: bool = False, - ) -> SphereCenterEstimates: - raise NotImplementedError - - @abc.abstractmethod - def estimate_sphere_center_2d(self) -> np.ndarray: - raise NotImplementedError - - @abc.abstractmethod - def estimate_sphere_center_3d( - self, - sphere_center_2d: np.ndarray, - prior_3d: T.Optional[np.ndarray] = None, - prior_strength: float = 0.0, - calculate_rms_residual: bool = False, - ) -> T.Tuple[np.array, T.Optional[float]]: - raise NotImplementedError - - # GAZE PREDICTION - @abc.abstractmethod - def _extract_unproject_disambiguate(self, pupil_datum: T.Dict) -> Circle: - raise NotImplementedError - - @abc.abstractmethod - def _disambiguate_circle_3d_pair( - self, circle_3d_pair: T.Tuple[Circle, Circle] - ) -> Circle: - raise NotImplementedError - - @abc.abstractmethod - def predict_pupil_circle( - self, observation: Observation, use_unprojection: bool = False - ) -> Circle: - raise NotImplementedError - - @abc.abstractmethod - def apply_refraction_correction(self, pupil_circle: Circle) -> Circle: - raise NotImplementedError - - @abc.abstractmethod - def mean_observation_circularity(self) -> float: - raise NotImplementedError - - @abc.abstractmethod - def cleanup(self): - raise NotImplementedError diff --git a/EyeTrackApp/pye3dcustom/eye_model/asynchronous.py b/EyeTrackApp/pye3dcustom/eye_model/asynchronous.py deleted file mode 100644 index afb840e..0000000 --- a/EyeTrackApp/pye3dcustom/eye_model/asynchronous.py +++ /dev/null @@ -1,320 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" - -import ctypes -import logging -import typing as T - -import numpy as np - -from ..constants import DEFAULT_SPHERE_CENTER -from .abstract import ( - TwoSphereModelAbstract, - CameraModel, - Circle, - Observation, - ObservationStorage, - SphereCenterEstimates, -) -from .background_helper import BackgroundProcess, mp -from .base import TwoSphereModel - -logger = logging.getLogger(__name__) - - -class TwoSphereModelAsync(TwoSphereModelAbstract): - def __init__( - self, - camera: CameraModel, - storage_cls: T.Type[ObservationStorage] = None, - storage_kwargs: T.Dict = None, - ): - synced_sphere_center = mp.Array(ctypes.c_double, 3) - synced_corrected_sphere_center = mp.Array(ctypes.c_double, 3) - synced_projected_sphere_center = mp.Array(ctypes.c_double, 2) - synced_observation_count = mp.Value(ctypes.c_long) - synced_rms_residual = mp.Value(ctypes.c_double) - is_estimation_ongoing_flag = mp.Event() - - self._frontend = _TwoSphereModelSyncedFrontend( - synced_sphere_center, - synced_corrected_sphere_center, - synced_projected_sphere_center, - synced_observation_count, - synced_rms_residual, - is_estimation_ongoing_flag, - camera=camera, - ) - self._backend_process = BackgroundProcess( - function=self._process_relayed_commands, - setup=self._setup_backend, - setup_args=( - synced_sphere_center, - synced_corrected_sphere_center, - synced_projected_sphere_center, - synced_observation_count, - synced_rms_residual, - is_estimation_ongoing_flag, - ), - setup_kwargs=dict( - camera=camera, - storage_cls=storage_cls, - storage_kwargs=storage_kwargs, - ), - cleanup=self._cleanup_backend, - log_handlers=logging.getLogger().handlers, - ) - - @property - def sphere_center(self) -> np.ndarray: - return self._frontend.sphere_center - - @property - def corrected_sphere_center(self) -> np.ndarray: - return self._frontend.corrected_sphere_center - - @property - def projected_sphere_center(self) -> np.ndarray: - return self._frontend.projected_sphere_center - - @property - def rms_residual(self) -> float: - return self._frontend.rms_residual - - def relay_command(self, function_name: str, *args, **kwargs): - self._backend_process.send(function_name, *args, **kwargs) - - @staticmethod - def _process_relayed_commands( - backend: "_TwoSphereModelSyncedBackend", function_name: str, *args, **kwargs - ): - function = getattr(backend, function_name) - return function(*args, **kwargs) - - @staticmethod - def _setup_backend(*args, **kwargs) -> "_TwoSphereModelSyncedBackend": - logger = logging.getLogger(__name__) - logger.debug(f"Setting up backend: {args}, {kwargs}") - return _TwoSphereModelSyncedBackend(*args, **kwargs) - - @staticmethod - def _cleanup_backend(backend: "_TwoSphereModelSyncedBackend"): - backend.cleanup() - logger = logging.getLogger(__name__) - logger.debug(f"Backend cleaned") - - def add_observation(self, observation: Observation): - self.relay_command("add_observation", observation) - - @property - def n_observations(self) -> int: - return self._frontend.n_observations - - def set_sphere_center(self, new_sphere_center: np.ndarray): - raise NotImplementedError - - def estimate_sphere_center( - self, - from_2d: T.Optional[np.ndarray] = None, - prior_3d: T.Optional[np.ndarray] = None, - prior_strength: float = 0.0, - calculate_rms_residual=False, - ) -> SphereCenterEstimates: - if not self._frontend._is_estimation_ongoing_flag.is_set(): - self.relay_command( - "estimate_sphere_center", - from_2d, - prior_3d, - prior_strength, - calculate_rms_residual, - ) - self._frontend._is_estimation_ongoing_flag.set() - projected_sphere_center = self._frontend.projected_sphere_center - sphere_center = self._frontend.sphere_center - rms_residual = self._frontend.rms_residual - return SphereCenterEstimates( - projected_sphere_center, sphere_center, rms_residual - ) - - def estimate_sphere_center_2d(self) -> np.ndarray: - raise NotImplementedError - - def estimate_sphere_center_3d( - self, - sphere_center_2d: np.ndarray, - prior_3d: T.Optional[np.ndarray] = None, - prior_strength: float = 0.0, - calculate_rms_residual: bool = False, - ) -> T.Tuple[np.array, T.Optional[float]]: - raise NotImplementedError - - # GAZE PREDICTION - def _extract_unproject_disambiguate(self, pupil_datum: T.Dict) -> Circle: - return self._frontend._extract_unproject_disambiguate(pupil_datum) - - def _disambiguate_circle_3d_pair( - self, circle_3d_pair: T.Tuple[Circle, Circle] - ) -> Circle: - return self._frontend._disambiguate_circle_3d_pair(circle_3d_pair) - - def predict_pupil_circle( - self, observation: Observation, use_unprojection: bool = False - ) -> Circle: - return self._frontend.predict_pupil_circle(observation, use_unprojection) - - def apply_refraction_correction(self, pupil_circle: Circle) -> Circle: - return self._frontend.apply_refraction_correction(pupil_circle) - - def cleanup(self): - logger.debug("Cancelling backend process") - self._backend_process.cancel() - self._frontend.cleanup() - - def mean_observation_circularity(self) -> float: - raise NotImplementedError - - -class _TwoSphereModelSyncedAbstract(TwoSphereModel): - def __init__( - self, - synced_sphere_center: mp.Array, # c_double_Array_3 - synced_corrected_sphere_center: mp.Array, # c_double_Array_3 - synced_projected_sphere_center: mp.Array, # c_double_Array_2 - synced_observation_count: mp.Value, # c_long - synced_rms_residual: mp.Value, # c_double - flag_is_estimation_ongoing: mp.Event, - **kwargs, - ): - self._synced_sphere_center = synced_sphere_center - self._synced_corrected_sphere_center = synced_corrected_sphere_center - self._synced_projected_sphere_center = synced_projected_sphere_center - self._synced_observation_count = synced_observation_count - self._synced_rms_residual = synced_rms_residual - self._is_estimation_ongoing_flag = flag_is_estimation_ongoing - super().__init__(**kwargs) - - @property - def sphere_center(self): - with self._synced_sphere_center: - return np.array(self._synced_sphere_center.get_obj()) - - @sphere_center.setter - def sphere_center(self, coordinates: np.array): - raise NotImplementedError - - @property - def corrected_sphere_center(self): - with self._synced_corrected_sphere_center: - return np.array(self._synced_corrected_sphere_center.get_obj()) - - @corrected_sphere_center.setter - def corrected_sphere_center(self, coordinates: np.array): - raise NotImplementedError - - @property - def projected_sphere_center(self): - with self._synced_projected_sphere_center: - return np.array(self._synced_projected_sphere_center.get_obj()) - - @projected_sphere_center.setter - def projected_sphere_center(self, coordinates: np.array): - raise NotImplementedError - - def mean_observation_circularity(self) -> float: - raise NotImplementedError - - @property - def rms_residual(self) -> float: - with self._synced_rms_residual: - return self._synced_rms_residual.value - - @rms_residual.setter - def rms_residual(self, residual: float): - raise NotImplementedError - - -class _TwoSphereModelSyncedFrontend(_TwoSphereModelSyncedAbstract): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - del self.storage # There is no storage in the frontend - - def _set_default_model_params(self): - with self._synced_sphere_center: - self._synced_sphere_center[:] = DEFAULT_SPHERE_CENTER - - corrected_sphere_center = self.refractionizer.correct_sphere_center( - np.asarray([[*self.sphere_center]]) - )[0] - with self._synced_corrected_sphere_center: - self._synced_corrected_sphere_center[:] = corrected_sphere_center - - @property - def n_observations(self) -> int: - return self._synced_observation_count.value - - -class _TwoSphereModelSyncedBackend(_TwoSphereModelSyncedAbstract): - @property - def sphere_center(self): - return super().sphere_center - - @sphere_center.setter - def sphere_center(self, coordinates: np.array): - with self._synced_sphere_center: - self._synced_sphere_center[:] = coordinates - - @property - def corrected_sphere_center(self): - return super().corrected_sphere_center - - @corrected_sphere_center.setter - def corrected_sphere_center(self, coordinates: np.array): - with self._synced_corrected_sphere_center: - self._synced_corrected_sphere_center[:] = coordinates - - @property - def projected_sphere_center(self): - return super().projected_sphere_center - - @projected_sphere_center.setter - def projected_sphere_center(self, coordinates: np.array): - with self._synced_projected_sphere_center: - self._synced_projected_sphere_center[:] = coordinates - - def add_observation(self, observation: Observation): - super().add_observation(observation=observation) - n_observations = super().n_observations - with self._synced_observation_count: - self._synced_observation_count.value = n_observations - - @property - def n_observations(self) -> int: - return self._synced_observation_count.value - - def estimate_sphere_center(self, *args, **kwargs): - result = super().estimate_sphere_center(*args, **kwargs) - self._is_estimation_ongoing_flag.clear() - return result - - def estimate_sphere_center_2d(self) -> np.ndarray: - estimated: np.ndarray = super().estimate_sphere_center_2d() - self.projected_sphere_center = estimated - return estimated - - @property - def rms_residual(self) -> float: - with self._synced_rms_residual: - return self._synced_rms_residual.value - - @rms_residual.setter - def rms_residual(self, residual: float): - with self._synced_rms_residual: - self._synced_rms_residual.value = residual diff --git a/EyeTrackApp/pye3dcustom/eye_model/background_helper.py b/EyeTrackApp/pye3dcustom/eye_model/background_helper.py deleted file mode 100644 index a2137e5..0000000 --- a/EyeTrackApp/pye3dcustom/eye_model/background_helper.py +++ /dev/null @@ -1,164 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2020 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" - -import logging -import multiprocessing as mp -import queue -import signal -import time -from ctypes import c_bool -from logging import Handler -from logging.handlers import QueueHandler, QueueListener -import traceback -from typing import Any, Callable, Dict, Iterable, Optional, Tuple, TypeVar - -logger = logging.getLogger(__name__) -WorkerSetupResult = TypeVar("WorkerSetupResult") -WorkerFunctionResult = TypeVar("WorkerFunctionResult") - - -class BackgroundProcess: - class StoppedError(Exception): - """Interaction with a BackgroundProcess that was stopped.""" - - class NothingToReceiveError(Exception): - """Trying to receive data from BackgroundProcess without sending input first.""" - - class MultipleSendError(Exception): - """Trying to send data without first receiving previous output.""" - - def __init__( - self, - setup: Callable[..., WorkerSetupResult], - function: Callable[[WorkerSetupResult], WorkerFunctionResult], - cleanup: Callable[[WorkerSetupResult], None], - setup_args: Optional[Tuple] = None, - setup_kwargs: Optional[Dict] = None, - log_handlers: Iterable[Handler] = (), - ): - self._running = True - - self._task_queue = mp.Queue(maxsize=500) # TODO: figure out good value - - logging_queue = mp.Queue() - self._log_listener = QueueListener(logging_queue, *log_handlers) - self._log_listener.start() - - self._should_terminate_flag = mp.Value(c_bool, 0) - - self._process = mp.Process( - name="Pye3D Background Process", - daemon=True, - target=BackgroundProcess._worker, - kwargs=dict( - setup=setup, - function=function, - cleanup=cleanup, - task_queue=self._task_queue, - should_terminate_flag=self._should_terminate_flag, - logging_queue=logging_queue, - setup_args=setup_args if setup_args else (), - setup_kwargs=setup_kwargs if setup_kwargs else {}, - ), - ) - self._process.start() - - @property - def running(self) -> bool: - """Whether background task is running (not necessarily doing work).""" - return self._running and self._process.is_alive() - - def send(self, *args: Tuple[Any], **kwargs: Dict[Any, Any]): - """Send data to background process for processing. - Raises StoppedError when called on a stopped process. - """ - - if not self.running: - logger.error("Background process was closed previously!") - raise BackgroundProcess.StoppedError() - - try: - self._task_queue.put_nowait({"args": args, "kwargs": kwargs}) - except queue.Full: - logger.debug(f"Dropping task! args: {args}, kwargs: {kwargs}") - - def cancel(self, timeout=-1): - """Stop process as soon as current task is finished.""" - - self._should_terminate_flag.value = 1 - if self.running: - self._task_queue.close() - self._task_queue.cancel_join_thread() - self._task_queue.join_thread() - self._process.join(timeout) - self._running = False - self._log_listener.stop() - - @staticmethod - def _install_sigint_interception(): - def interrupt_handler(sig, frame): - import traceback - - trace = traceback.format_stack(f=frame) - logger.debug(f"Caught (and dropping) signal {sig} in:\n" + "".join(trace)) - - signal.signal(signal.SIGINT, interrupt_handler) - - @staticmethod - def _worker( - setup: Callable[..., WorkerSetupResult], - function: Callable[[WorkerSetupResult], Any], - cleanup: Callable[[WorkerSetupResult], None], - task_queue: mp.Queue, - should_terminate_flag: mp.Value, - logging_queue: mp.Queue, - setup_args: Tuple, - setup_kwargs: Dict, - ): - log_queue_handler = QueueHandler(logging_queue) - logger = logging.getLogger() - logger.setLevel(logging.NOTSET) - logger.addHandler(log_queue_handler) - - # Intercept SIGINT (ctrl-c), do required cleanup in foreground process! - BackgroundProcess._install_sigint_interception() - - setup_result: WorkerSetupResult = setup(*setup_args, **setup_kwargs) - - while not should_terminate_flag.value: - try: - params = task_queue.get(block=True, timeout=0.1) - args = params["args"] - kwargs = params["kwargs"] - except queue.Empty: - continue - # except EOFError: - # logger.info("Pipe was closed from foreground process .") - # break - - try: - t0 = time.perf_counter() - function(setup_result, *args, **kwargs) - t1 = time.perf_counter() - # logger.debug(f"Finished background calculation in {(t1 - t0):.2}s") - except Exception as e: - logger.error( - f"Error executing background process with parameters {params}:\n{e}" - ) - logger.debug(traceback.format_exc()) - break - else: - logger.info("Background process received termination signal.") - - cleanup(setup_result) - - logger.info("Stopping background process.") - logger.removeHandler(log_queue_handler) diff --git a/EyeTrackApp/pye3dcustom/eye_model/base.py b/EyeTrackApp/pye3dcustom/eye_model/base.py deleted file mode 100644 index 34be720..0000000 --- a/EyeTrackApp/pye3dcustom/eye_model/base.py +++ /dev/null @@ -1,297 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import logging -import typing as T - -import numpy as np - -from .abstract import TwoSphereModelAbstract, SphereCenterEstimates -from ..camera import CameraModel -from ..constants import _EYE_RADIUS_DEFAULT, DEFAULT_SPHERE_CENTER -from ..geometry.intersections import nearest_point_on_sphere_to_line -from ..geometry.primitives import Circle, Line -from ..geometry.projections import ( - project_line_into_image_plane, - project_point_into_image_plane, - unproject_ellipse, -) -from ..geometry.utilities import normalize -from ..observation import BasicStorage, Observation, ObservationStorage -from ..refraction import Refractionizer - -logger = logging.getLogger(__name__) - - -class TwoSphereModel(TwoSphereModelAbstract): - def __init__( - self, - camera: CameraModel, - storage_cls: T.Type[ObservationStorage] = None, - storage_kwargs: T.Dict = None, - ): - if storage_cls: - kwargs = storage_kwargs if storage_kwargs is not None else {} - self.storage = storage_cls(**kwargs) - else: - self.storage = BasicStorage() - self.camera = camera - - self.refractionizer = Refractionizer() - self._set_default_model_params() - - @property - def sphere_center(self) -> np.ndarray: - return self._sphere_center - - @sphere_center.setter - def sphere_center(self, coordinates: np.ndarray): - self._sphere_center = coordinates - - @property - def corrected_sphere_center(self) -> np.ndarray: - return self._corrected_sphere_center - - @corrected_sphere_center.setter - def corrected_sphere_center(self, coordinates: np.ndarray): - self._corrected_sphere_center = coordinates - - @property - def projected_sphere_center(self) -> np.ndarray: - return self._projected_sphere_center - - @projected_sphere_center.setter - def projected_sphere_center(self, projected_sphere_center: np.ndarray): - self._projected_sphere_center = projected_sphere_center - - def _set_default_model_params(self): - # Overwrite in subclasses that do not allow setting these attributes - self._sphere_center = np.asarray(DEFAULT_SPHERE_CENTER) - self._corrected_sphere_center = self.refractionizer.correct_sphere_center( - np.asarray([[*self.sphere_center]]) - )[0] - self.rms_residual = np.nan - - def add_observation(self, observation: Observation): - self.storage.add(observation) - - @property - def n_observations(self) -> int: - return self.storage.count() - - def set_sphere_center(self, new_sphere_center): - self.sphere_center = new_sphere_center - self.corrected_sphere_center = self.refractionizer.correct_sphere_center( - np.asarray([[*self.sphere_center]]) - )[0] - - def estimate_sphere_center( - self, - from_2d=None, - prior_3d=None, - prior_strength=0.0, - calculate_rms_residual=False, - ): - self.projected_sphere_center = ( - from_2d if from_2d is not None else self.estimate_sphere_center_2d() - ) - sphere_center, rms_residual = self.estimate_sphere_center_3d( - self.projected_sphere_center, - prior_3d, - prior_strength, - calculate_rms_residual=calculate_rms_residual, - ) - self.set_sphere_center(sphere_center) - self.rms_residual = rms_residual if rms_residual is not None else float("nan") - return SphereCenterEstimates( - self.projected_sphere_center, sphere_center, rms_residual - ) - - def estimate_sphere_center_2d(self): - observations = self.storage.observations - - # slightly faster than np.array - aux_2d = np.concatenate([obs.aux_2d for obs in observations]) - aux_2d.shape = -1, 2, 3 - - # Estimate projected sphere center by nearest intersection of 2d gaze lines - sum_aux_2d = aux_2d.sum(axis=0) - projected_sphere_center = np.linalg.pinv(sum_aux_2d[:2, :2]) @ sum_aux_2d[:2, 2] - - return projected_sphere_center - - def estimate_sphere_center_3d( - self, - sphere_center_2d, - prior_3d=None, - prior_strength=0.0, - calculate_rms_residual=False, - ) -> T.Tuple[np.array, T.Optional[float]]: - observations, aux_3d, gaze_2d = self._prep_data() - sum_aux_3d, disamb_indices, aux_3d_disamb = self._disambiguate_dierkes_lines( - aux_3d, gaze_2d, sphere_center_2d - ) - sphere_center = self._calc_sphere_center(sum_aux_3d, prior_3d, prior_strength) - - rms_residual = ( - self._calc_rms_residual( - observations, disamb_indices, sphere_center, aux_3d_disamb - ) - if calculate_rms_residual - else None - ) - - return sphere_center, rms_residual - - def _prep_data(self): - observations = self.storage.observations - aux_3d = np.concatenate([obs.aux_3d for obs in observations]) - aux_3d.shape = -1, 2, 3, 4 - gaze_2d = np.concatenate([obs.gaze_2d_line for obs in observations]) - gaze_2d.shape = -1, 4 - return observations, aux_3d, gaze_2d - - def _disambiguate_dierkes_lines(self, aux_3d, gaze_2d, sphere_center_2d): - # Disambiguate Dierkes lines - # We want gaze_2d to points towards the sphere center. gaze_2d was collected - # from Dierkes[0]. If it points into the correct direction, we know that - # Dierkes[0] is the correct one to use, otherwise we need to use Dierkes[1]. We - # can check that with the sign of the dot product. - gaze_2d_origins = gaze_2d[:, :2] - gaze_2d_directions = gaze_2d[:, 2:] - gaze_2d_towards_center = gaze_2d_origins - sphere_center_2d - - dot_products = np.sum(gaze_2d_towards_center * gaze_2d_directions, axis=1) - disambiguation_indices = np.where(dot_products < 0, 1, 0) - - obs_idc = np.arange(disambiguation_indices.shape[0]) - aux_3d_disambiguated = aux_3d[obs_idc, disambiguation_indices, :, :] - - # Estimate sphere center by nearest intersection of Dierkes lines - sum_aux_3d = aux_3d_disambiguated.sum(axis=0) - return sum_aux_3d, disambiguation_indices, aux_3d_disambiguated - - def _calc_sphere_center(self, sum_aux_3d, prior_3d=None, prior_strength=0.0): - matrix = sum_aux_3d[:3, :3] - try: - if prior_3d is None: - return np.linalg.pinv(matrix) @ sum_aux_3d[:3, 3] - else: - return np.linalg.pinv(matrix + prior_strength * np.eye(3)) @ ( - sum_aux_3d[:3, 3] + prior_strength * prior_3d - ) - except np.linalg.LinAlgError: - # happens if lines are parallel, very rare - return DEFAULT_SPHERE_CENTER - - def _calc_rms_residual( - self, observations, disamb_indices, sphere_center, aux_3d_disamb - ): - # Here we use eq. (10) in https://docplayer.net/21072949-Least-squares-intersection-of-lines.html. - origins_dierkes_lines = np.array( - [ - obs.get_Dierkes_line(idx).origin - for obs, idx in zip(observations, disamb_indices) - ] - ) - origins_dierkes_lines.shape = -1, 3, 1 - deltas = origins_dierkes_lines - sphere_center[:, np.newaxis] - tmp = np.einsum("ijk,ikl->ijl", aux_3d_disamb[:, :3, :3], deltas) - squared_residuals = np.einsum( - "ikj,ijk->i", np.transpose(deltas, (0, 2, 1)), tmp - ) - rms_residual = np.clip(squared_residuals, 0.0, None) - rms_residual = np.mean(np.sqrt(rms_residual)) - return rms_residual - - # GAZE PREDICTION - def _extract_unproject_disambiguate(self, pupil_datum): - ellipse = self._extract_ellipse(pupil_datum) - circle_3d_pair = unproject_ellipse(ellipse, self.camera.focal_length) - if circle_3d_pair: - circle_3d = self._disambiguate_circle_3d_pair(circle_3d_pair) - else: - circle_3d = Circle([0.0, 0.0, 0.0], [0.0, 0.0, -1.0], 0.0) - return circle_3d - - def _disambiguate_circle_3d_pair(self, circle_3d_pair): - circle_center_2d = project_point_into_image_plane( - circle_3d_pair[0].center, self.camera.focal_length - ) - circle_normal_2d = normalize( - project_line_into_image_plane( - Line(circle_3d_pair[0].center, circle_3d_pair[0].normal), - self.camera.focal_length, - ).direction - ) - sphere_center_2d = project_point_into_image_plane( - self.sphere_center, self.camera.focal_length - ) - - if np.dot(circle_center_2d - sphere_center_2d, circle_normal_2d) >= 0: - return circle_3d_pair[0] - else: - return circle_3d_pair[1] - - def predict_pupil_circle( - self, observation: Observation, use_unprojection: bool = False - ) -> Circle: - if observation.invalid: - return Circle.null() - - circle_3d = self._disambiguate_circle_3d_pair(observation.circle_3d_pair) - unprojection_depth = np.linalg.norm(circle_3d.center) - direction = circle_3d.center / unprojection_depth - - nearest_point_on_sphere = nearest_point_on_sphere_to_line( - self.sphere_center, _EYE_RADIUS_DEFAULT, [0.0, 0.0, 0.0], direction - ) - - if use_unprojection: - gaze_vector = circle_3d.normal - else: - gaze_vector = normalize(nearest_point_on_sphere - self.sphere_center) - - radius = np.linalg.norm(nearest_point_on_sphere) / unprojection_depth - pupil_circle = Circle(nearest_point_on_sphere, gaze_vector, radius) - return pupil_circle - - def apply_refraction_correction(self, pupil_circle): - input_features = np.asarray( - [[*self.sphere_center, *pupil_circle.normal, pupil_circle.radius]] - ) - refraction_corrected_params = self.refractionizer.correct_pupil_circle( - input_features - )[0] - - refraction_corrected_gaze_vector = normalize(refraction_corrected_params[:3]) - refraction_corrected_radius = refraction_corrected_params[-1] - refraction_corrected_pupil_center = ( - self.corrected_sphere_center - + _EYE_RADIUS_DEFAULT * refraction_corrected_gaze_vector - ) - - refraction_corrected_pupil_circle = Circle( - refraction_corrected_pupil_center, - refraction_corrected_gaze_vector, - refraction_corrected_radius, - ) - - return refraction_corrected_pupil_circle - - def mean_observation_circularity(self): - observation_circularities = [ - observation.ellipse.circularity() - for observation in self.storage.observations - ] - return np.mean(observation_circularities) - - def cleanup(self): - pass diff --git a/EyeTrackApp/pye3dcustom/geometry/__init__.py b/EyeTrackApp/pye3dcustom/geometry/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/EyeTrackApp/pye3dcustom/geometry/intersections.py b/EyeTrackApp/pye3dcustom/geometry/intersections.py deleted file mode 100644 index fe5faf6..0000000 --- a/EyeTrackApp/pye3dcustom/geometry/intersections.py +++ /dev/null @@ -1,161 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import numpy as np - - -def intersect_line_line(p11, p12, p21, p22, internal=False): - x1, y1 = p11 - x2, y2 = p12 - x3, y3 = p21 - x4, y4 = p22 - - if ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)) != 0: - Px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ( - (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) - ) - Py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ( - (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) - ) - if internal: - if x1 != x2: - lam = (Px - x2) / (x1 - x2) - else: - lam = (Py - y2) / (y1 - y2) - if 0 <= lam <= 1: - return [True, Px, Py] - else: - return [False] - else: - return [True, Px, Py] - else: - return [False] - - -def intersect_sphere_multiple_lines(sphere_center, radius, points, directions): - # Note: Directions need to be normalized! - intermediate = np.einsum("ij,ij->i", directions, points - sphere_center) - discriminant = ( - intermediate ** 2 - np.sum((points - sphere_center) ** 2, axis=1) + radius ** 2 - ) - idx = discriminant > 0 - sqr = np.sqrt(discriminant[idx]) - d1 = -intermediate[idx] + sqr - d2 = -intermediate[idx] - sqr - d_final = np.expand_dims(np.minimum(d1, d2), axis=1) - intersections_on_sphere = points[idx] + d_final * directions[idx] - - return intersections_on_sphere, idx - - -def intersect_sphere_line(sphere_center, radius, point, direction): - temp = np.dot(direction, point - sphere_center) - discriminant = temp ** 2 - np.linalg.norm(point - sphere_center) ** 2 + radius ** 2 - if discriminant >= 0.0: - sqr = np.sqrt(discriminant) - d1 = -temp + sqr - d2 = -temp - sqr - return [True, d1, d2] - else: - return [False, 0.0, 0.0] - - -def intersect_plane_line(p_plane, n_plane, p_line, l_line, radius=-1): - if np.dot(n_plane, l_line) == 0 or np.dot(p_plane - p_line, n_plane) == 0: - return [False] - else: - d = np.dot(p_plane - p_line, n_plane) / np.dot(l_line, n_plane) - p_intersect = p_line + d * l_line - if radius > 0: - if np.linalg.norm(p_plane - p_intersect) <= radius[0]: - return [True, p_intersect[0], p_intersect[1], p_intersect[2]] - else: - return [False, 0.0, 0.0, 0.0] - else: - return [True, p_intersect[0], p_intersect[1], p_intersect[2]] - - -def nearest_point_on_sphere_to_line(center, radius, origin, direction): - intersection = intersect_sphere_line(center, radius, origin, direction) - if intersection[0]: - d = np.min(intersection[1:]) - return origin + d * direction - else: - temp = np.dot(direction, center - origin) - origin_prime = origin + temp * direction - direction_prime = center - origin_prime - direction_prime /= np.linalg.norm(direction_prime) - success, d1, d2 = intersect_sphere_line( - center, radius, origin_prime, direction_prime - ) - if success: - d = min(d1, d2) - return origin_prime + d * direction_prime - else: - np.zeros(3) - - -def nearest_intersection_points(p1, p2, p3, p4): - """Calculates the two nearest points, and their distance to each other on - two lines defined by (p1,p2) respectively (p3,p4) - """ - - def mag(p): - return np.sqrt(p.dot(p)) - - def normalise(p1, p2): - p = p2 - p1 - m = mag(p) - if m == 0: - return [0.0, 0.0, 0.0] - else: - return p / m - - d1 = normalise(p1, p2) - d2 = normalise(p3, p4) - - diff = p1 - p3 - a01 = -d1.dot(d2) - b0 = diff.dot(d1) - - if np.abs(a01) < 1.0: - - # Lines are not parallel. - det = 1.0 - a01 * a01 - b1 = -diff.dot(d2) - s0 = (a01 * b1 - b0) / det - s1 = (a01 * b0 - b1) / det - - else: - - # Lines are parallel, select any pair of closest points. - s0 = -b0 - s1 = 0 - - closestPoint1 = p1 + s0 * d1 - closestPoint2 = p3 + s1 * d2 - dist = mag(closestPoint2 - closestPoint1) - - return closestPoint1, closestPoint2, dist - - -def nearest_intersection_lines(lines): - dim = len(lines[0].origin) - - R = np.zeros((dim, dim)) - q = np.zeros(dim) - - for line in lines: - v = np.reshape(line.direction, (dim, 1)) - A = np.eye(dim) - v @ v.T - R += A - q += A @ line.origin - - return np.linalg.pinv(R) @ q diff --git a/EyeTrackApp/pye3dcustom/geometry/primitives.py b/EyeTrackApp/pye3dcustom/geometry/primitives.py deleted file mode 100644 index 2c92f98..0000000 --- a/EyeTrackApp/pye3dcustom/geometry/primitives.py +++ /dev/null @@ -1,188 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import abc - -import numpy as np - -from .utilities import cart2sph, normalize - - -class Primitive(abc.ABC): - __slots__ = () - - def __repr__(self): - klass = "{}.{}".format(self.__class__.__module__, self.__class__.__name__) - attributes = " ".join( - "{}={}".format(k, v.__repr__()) for k, v in self.__dict__.items() - ) - return "<{klass} at {id}: {attributes}>".format( - klass=klass, id=id(self), attributes=attributes - ) - - def __str__(self): - def to_str(obj, float_fmt="{:f}") -> str: - if isinstance(obj, float) or isinstance(obj, int): - return float_fmt.format(obj) - if isinstance(obj, np.ndarray): - if obj.dtype != np.object: - return ", ".join(float_fmt.format(x) for x in obj) - return str(obj) - - klass = self.__class__.__name__ - attributes = " - ".join( - "{}: {}".format(k, to_str(v)) for k, v in self.__dict__.items() - ) - return "{klass} -> {attributes}".format(klass=klass, attributes=attributes) - - -class Line(Primitive): - __slots__ = ("origin", "direction", "dim") - - def __init__(self, origin, direction): - self.origin = np.asarray(origin) - self.direction = normalize(np.asarray(direction)) - self.dim = self.origin.shape[0] - - -class Circle(Primitive): - __slots__ = ("center", "normal", "radius") - - def __init__(self, center=[0.0, 0.0, 0.0], normal=[0.0, 0.0, -1.0], radius=0.0): - self.center = np.asarray(center, dtype=float) - self.normal = np.asarray(normal, dtype=float) - self.radius = radius - - def spherical_representation(self): - phi, theta = cart2sph(self.normal) - return phi, theta, self.radius - - def is_null(self): - return self.radius <= 0.0 - - @staticmethod - def null() -> "Circle": - return Circle(radius=0.0) - - -class Ellipse(Primitive): - __slots__ = ("center", "major_radius", "minor_radius", "angle") - - def __init__(self, center, minor_radius, major_radius, angle): - self.center = center - self.major_radius = major_radius - self.minor_radius = minor_radius - self.angle = angle - - if self.minor_radius > self.major_radius: - current_minor_radius = self.minor_radius - self.minor_radius = self.major_radius - self.major_radius = current_minor_radius - self.angle = self.angle + np.pi / 2 - - def circumference(self): - a = self.minor_radius - b = self.major_radius - return np.pi * (3.0 * (a + b) - np.sqrt((3.0 * a + b) * (a + 3.0 * b))) - - def area(self): - return np.pi * self.minor_radius * self.major_radius - - def circularity(self): - return self.minor_radius / self.major_radius - - def parameters(self): - return ( - self.center[0], - self.center[1], - self.minor_radius, - self.major_radius, - self.angle, - ) - - -class Sphere(Primitive): - __slots__ = ("center", "radius") - - def __init__(self, center, radius): - self.center = center - self.radius = radius - - def __bool__(self): - return self.radius > 0 - - -class Conicoid(Primitive): - """ - Coefficients of the general equation (implicit form) of a cone, given its vertex and base (ellipse/conic). - Formulae follow equations (1)-(3) of: - Safaee-Rad, R. et al.: "Three-Dimensional Location Estimation of Circular Features for Machine Vision", - IEEE Transactions on Robotics and Automation, Vol.8(5), 1992, pp624-640. - """ - - __slots__ = tuple("ABCFGHUVWD") - - def __init__(self, conic, vertex): - alpha = vertex[0] - beta = vertex[1] - gamma = vertex[2] - self.A = (gamma ** 2) * conic.A - self.B = (gamma ** 2) * conic.C - self.C = ( - conic.A * (alpha ** 2) - + conic.B * alpha * beta - + conic.C * (beta ** 2) - + conic.D * alpha - + conic.E * beta - + conic.F - ) - self.F = -gamma * (conic.C * beta + conic.B / 2 * alpha + conic.E / 2) - self.G = -gamma * (conic.B / 2 * beta + conic.A * alpha + conic.D / 2) - self.H = (gamma ** 2) * conic.B / 2 - self.U = (gamma ** 2) * conic.D / 2 - self.V = (gamma ** 2) * conic.E / 2 - self.W = -gamma * (conic.E / 2 * beta + conic.D / 2 * alpha + conic.F) - self.D = (gamma ** 2) * conic.F - - -class Conic(Primitive): - """ - Coefficients A-F of the general equation (implicit form) of a conic - Ax² + Bxy + Cy² + Dx + Ey + F = 0 - calculated from 5 ellipse parameters, see https://en.wikipedia.org/wiki/Ellipse#General_ellipse - """ - - __slots__ = tuple("ABCDEF") - - def __init__(self, *args): - if len(args) == 1: - ellipse = args[0] - ax = np.cos(ellipse.angle) - ay = np.sin(ellipse.angle) - a2 = ellipse.major_radius ** 2 - b2 = ellipse.minor_radius ** 2 - - self.A = a2 * ay * ay + b2 * ax * ax - self.B = 2.0 * (b2 - a2) * ax * ay - self.C = a2 * ax * ax + b2 * ay * ay - self.D = -2.0 * self.A * ellipse.center[0] - self.B * ellipse.center[1] - self.E = -self.B * ellipse.center[0] - 2.0 * self.C * ellipse.center[1] - self.F = ( - self.A * ellipse.center[0] * ellipse.center[0] - + self.B * ellipse.center[0] * ellipse.center[1] - + self.C * ellipse.center[1] * ellipse.center[1] - - a2 * b2 - ) - - if len(args) == 6: - self.A, self.B, self.C, self.D, self.E, self.F = args - - def discriminant(self): - return self.B ** 2 - 4 * self.A * self.C diff --git a/EyeTrackApp/pye3dcustom/geometry/projections.py b/EyeTrackApp/pye3dcustom/geometry/projections.py deleted file mode 100644 index 0dc4e66..0000000 --- a/EyeTrackApp/pye3dcustom/geometry/projections.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import logging -import warnings - -import numpy as np - -from .intersections import intersect_sphere_multiple_lines -from .primitives import Circle, Conic, Conicoid, Ellipse, Line -from .utilities import normalize -from ..cpp.projections import unproject_ellipse - -logger = logging.getLogger(__name__) - - -def unproject_edges_to_sphere( - edges, focal_length, sphere_center, sphere_radius, width=640, height=480 -): - n_edges = edges.shape[0] - - directions = edges - np.asarray([width / 2.0, height / 2.0]) - directions = np.hstack((directions, focal_length * np.ones((n_edges, 1)))) - directions = directions / np.linalg.norm(directions, axis=1, keepdims=1) - - origins = np.zeros((n_edges, 3)) - - edges_on_sphere, idxs = intersect_sphere_multiple_lines( - sphere_center, sphere_radius, origins, directions - ) - - return edges_on_sphere, idxs - - -def project_point_into_image_plane(point, focal_length): - scale = focal_length / point[2] - point_projected = scale * np.asarray(point) - return point_projected[:2] - - -def project_line_into_image_plane(line, focal_length): - p1 = line.origin - p2 = line.origin + line.direction - - p1_projected = project_point_into_image_plane(p1, focal_length) - p2_projected = project_point_into_image_plane(p2, focal_length) - - return Line(p1_projected, p2_projected - p1_projected) - - -def project_circle_into_image_plane( - circle, focal_length, transform=True, width=0, height=0 -): - c = circle.center - n = circle.normal - r = circle.radius - f = focal_length - - cn = np.dot(c, n) - c2r2 = np.dot(c, c) - r ** 2 - ABC = cn ** 2 - 2.0 * cn * (c * n) + c2r2 * (n ** 2) - F = 2.0 * (c2r2 * n[1] * n[2] - cn * (n[1] * c[2] + n[2] * c[1])) - G = 2.0 * (c2r2 * n[2] * n[0] - cn * (n[2] * c[0] + n[0] * c[2])) - H = 2.0 * (c2r2 * n[0] * n[1] - cn * (n[0] * c[1] + n[1] * c[0])) - conic = Conic(ABC[0], H, ABC[1], G * f, F * f, ABC[2] * f ** 2) - - disc_ = conic.discriminant() - - if disc_ < 0: - - A, B, C, D, E, F = conic.A, conic.B, conic.C, conic.D, conic.E, conic.F - center_x = (2 * C * D - B * E) / disc_ - center_y = (2 * A * E - B * D) / disc_ - temp_ = 2 * (A * E ** 2 + C * D ** 2 - B * D * E + disc_ * F) - minor_axis = ( - -np.sqrt(np.abs(temp_ * (A + C - np.sqrt((A - C) ** 2 + B ** 2)))) / disc_ - ) # Todo: Absolute value??? - major_axis = ( - -np.sqrt(np.abs(temp_ * (A + C + np.sqrt((A - C) ** 2 + B ** 2)))) / disc_ - ) - - if B == 0 and A < C: - angle = 0 - elif B == 0 and A >= C: - angle = np.pi / 2.0 - else: - angle = np.arctan((C - A - np.sqrt((A - C) ** 2 + B ** 2)) / B) - - # TO BE CONSISTENT WITH PUPIL - if transform: - center_x = center_x + width / 2.0 - center_y = center_y + height / 2.0 - minor_axis, major_axis = 2.0 * minor_axis, 2.0 * major_axis - angle = angle * 180.0 / np.pi + 90.0 - - return Ellipse(np.asarray([center_x, center_y]), minor_axis, major_axis, angle) - - else: - - return False - - -def project_sphere_into_image_plane( - sphere, focal_length, transform=True, width=0, height=0 -): - scale = focal_length / sphere.center[2] - - projected_sphere_center = scale * sphere.center - projected_radius = scale * sphere.radius - - if transform: - projected_sphere_center[0] += width / 2.0 - projected_sphere_center[1] += height / 2 - projected_radius *= 2.0 - - return Ellipse(projected_sphere_center[:2], projected_radius, projected_radius, 0.0) diff --git a/EyeTrackApp/pye3dcustom/geometry/utilities.py b/EyeTrackApp/pye3dcustom/geometry/utilities.py deleted file mode 100644 index f4cabc5..0000000 --- a/EyeTrackApp/pye3dcustom/geometry/utilities.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import numpy as np - - -def cart2sph(x): - - phi = np.arctan2(x[2], x[0]) - theta = np.arccos(x[1] / np.linalg.norm(x)) - - return phi, theta - - -def sph2cart(phi, theta): - - result = np.empty(3) - - result[0] = np.sin(theta) * np.cos(phi) - result[1] = np.cos(theta) - result[2] = np.sin(theta) * np.sin(phi) - - return result - - -def normalize(v, axis=-1): - - return v / np.linalg.norm(v, axis=axis) - - -def enclosed_angle(v1, v2, unit="deg", axis=-1): - - v1 = normalize(v1, axis=axis) - v2 = normalize(v2, axis=axis) - - alpha = np.arccos(np.clip(np.dot(v1.T, v2), -1, 1)) - - if unit == "deg": - return 180.0 / np.pi * alpha - else: - return alpha - - -def make_homogeneous_vector(v): - - return np.hstack((v, [0.0])) - - -def make_homogeneous_point(p): - return np.hstack((p, [1.0])) - - -def transform_as_homogeneous_point(p, trafo): - p = make_homogeneous_point(p) - return (trafo @ p)[:3] - - -def transform_as_homogeneous_vector(v, trafo): - v = make_homogeneous_vector(v) - return (trafo @ v)[:3] - - -def rotate_v1_on_v2(v1, v2): - - v1 = normalize(v1) - v2 = normalize(v2) - cos_angle = np.dot(v1, v2) - - if not np.allclose(np.abs(cos_angle), 1): - u = np.cross(v1, v2) - s = np.linalg.norm(u) - c = np.dot(v1, v2) - - I = np.eye(3) - ux = np.asarray([[0, -u[2], u[1]], [u[2], 0, -u[0]], [-u[1], u[0], 0]]) - - R = I + ux + np.dot(ux, ux) * (1 - c) / s ** 2 - - elif np.allclose(cos_angle, 1): - R = np.eye(3) - - elif np.allclose(cos_angle, -1): - R = -np.eye(3) - - return R diff --git a/EyeTrackApp/pye3dcustom/kalman.py b/EyeTrackApp/pye3dcustom/kalman.py deleted file mode 100644 index 282fead..0000000 --- a/EyeTrackApp/pye3dcustom/kalman.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -import cv2 -import numpy as np - - -class KalmanFilter(object): - def __init__(self): - self.filter = cv2.KalmanFilter(7, 3, 0, cv2.CV_32F) - self.filter.measurementMatrix = np.asarray( - [[1, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1]], - dtype=np.float32, - ) - self.filter.processNoiseCov = 1e-4 * np.eye(7, dtype=np.float32) - self.filter.measurementNoiseCov = 1e-5 * np.eye(3, dtype=np.float32) - self.filter.measurementNoiseCov[2][2] = 0.1 - self.filter.statePost = np.asarray([0, 0, 0, 0, 0, 0, 2.0], dtype=np.float32) - self.filter.errorCovPost = np.eye(7, dtype=np.float32) - self.last_call = -1 - - def predict(self, t): - if self.last_call != -1 and t > self.last_call: - dt = t - self.last_call - self.filter.transitionMatrix = np.asarray( - [ - [1, 0, dt, 0, 0.5 * dt * dt, 0, 0], - [0, 1, 0, dt, 0, 0.5 * dt * dt, 0], - [0, 0, 1, 0, dt, 0, 0], - [0, 0, 0, 1, 0, dt, 0], - [0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 1], - ], - dtype=np.float32, - ) - prediction = self.filter.predict() - phi, theta, pupil_radius = ( - prediction[0][0], - prediction[1][0], - prediction[6][0], - ) - else: - phi, theta, pupil_radius = -np.pi / 2, np.pi / 2, 0 - - self.last_call = t - - return phi, theta, pupil_radius - - def correct(self, phi, theta, radius): - self.filter.correct(np.asarray([phi, theta, radius], dtype=np.float32)) diff --git a/EyeTrackApp/pye3dcustom/observation.py b/EyeTrackApp/pye3dcustom/observation.py deleted file mode 100644 index dfdd9b0..0000000 --- a/EyeTrackApp/pye3dcustom/observation.py +++ /dev/null @@ -1,232 +0,0 @@ -""" -(*)~--------------------------------------------------------------------------- -Pupil - eye tracking platform -Copyright (C) 2012-2019 Pupil Labs - -Distributed under the terms of the GNU -Lesser General Public License (LGPL v3.0). -See COPYING and COPYING.LESSER for license details. ----------------------------------------------------------------------------~(*) -""" -from abc import abstractmethod, abstractproperty -from collections import deque -from math import floor -from typing import Sequence, Optional - -import numpy as np -from sortedcontainers import SortedList - -from .camera import CameraModel -from .constants import _EYE_RADIUS_DEFAULT -from .geometry.primitives import Ellipse, Line -from .geometry.projections import project_line_into_image_plane, unproject_ellipse - - -class Observation(object): - def __init__( - self, ellipse: Ellipse, confidence: float, timestamp: float, focal_length: float - ): - self.ellipse = ellipse - self.confidence_2d = confidence - self.confidence = 0.0 - self.timestamp = timestamp - - self.circle_3d_pair = None - self.gaze_3d_pair = None - self.gaze_2d = None - self.aux_2d = None - self.aux_3d = None - self.invalid = True - - circle_3d_pair = unproject_ellipse(ellipse, focal_length) - if not circle_3d_pair: - # unprojecting ellipse failed, invalid observation! - return - - self.invalid = False - self.confidence = self.confidence_2d - self.circle_3d_pair = circle_3d_pair - - self.gaze_3d_pair = [ - Line( - circle_3d_pair[i].center, - circle_3d_pair[i].center + circle_3d_pair[i].normal, - ) - for i in [0, 1] - ] - self.gaze_2d = project_line_into_image_plane(self.gaze_3d_pair[0], focal_length) - self.gaze_2d_line = np.array([*self.gaze_2d.origin, *self.gaze_2d.direction]) - - self.aux_2d = np.empty((2, 3)) - v = np.reshape(self.gaze_2d.direction, (2, 1)) - self.aux_2d[:, :2] = np.eye(2) - v @ v.T - self.aux_2d[:, 2] = (np.eye(2) - v @ v.T) @ self.gaze_2d.origin - - self.aux_3d = np.empty((2, 3, 4)) - for i in range(2): - Dierkes_line = self.get_Dierkes_line(i) - v = np.reshape(Dierkes_line.direction, (3, 1)) - self.aux_3d[i, :3, :3] = np.eye(3) - v @ v.T - self.aux_3d[i, :3, 3] = (np.eye(3) - v @ v.T) @ Dierkes_line.origin - - def get_Dierkes_line(self, i): - origin = ( - self.circle_3d_pair[i].center - - _EYE_RADIUS_DEFAULT * self.circle_3d_pair[i].normal - ) - direction = self.circle_3d_pair[i].center - return Line(origin, direction) - - -class ObservationStorage: - @abstractmethod - def add(self, observation: Observation): - pass - - @abstractproperty - def observations(self) -> Sequence[Observation]: - pass - - @abstractmethod - def clear(self): - pass - - @abstractmethod - def count(self) -> int: - pass - - -class BasicStorage(ObservationStorage): - def __init__(self): - self._storage = [] - - def add(self, observation: Observation): - if observation.invalid: - return - self._storage.append(observation) - - @property - def observations(self) -> Sequence[Observation]: - return self._storage - - def clear(self): - self._storage.clear() - - def count(self) -> int: - return len(self._storage) - - -class BufferedObservationStorage(ObservationStorage): - def __init__(self, confidence_threshold: float, buffer_length: int): - self.confidence_threshold = confidence_threshold - self._storage = deque(maxlen=buffer_length) - - def add(self, observation: Observation): - if observation.invalid: - return - if observation.confidence < self.confidence_threshold: - return - - self._storage.append(observation) - - @property - def observations(self) -> Sequence[Observation]: - return list(self._storage) - - def clear(self): - self._storage.clear() - - def count(self) -> int: - return len(self._storage) - - -class BinBufferedObservationStorage(ObservationStorage): - def __init__( - self, - camera: CameraModel, - confidence_threshold: float, - n_bins_horizontal: int, - bin_buffer_length: int, - forget_min_observations: Optional[int] = None, - forget_min_time: Optional[float] = None, - ): - self.camera = camera - self.confidence_threshold = confidence_threshold - self.bin_buffer_length = bin_buffer_length - self.forget_min_observations = forget_min_observations - self.forget_min_time = forget_min_time - self.pixels_per_bin = self.camera.resolution[0] / n_bins_horizontal - self.w = n_bins_horizontal - self.h = int(round(self.camera.resolution[1] / self.pixels_per_bin)) - - self._by_time = SortedList(key=lambda obs: obs.timestamp) - self._by_bin = dict() - - def add(self, observation: Observation): - if observation.invalid: - return - if observation.confidence < self.confidence_threshold: - return - - idx = self._get_bin(observation) - if idx < 0 or idx >= self.w * self.h: - print(f"INDEX OUT OF BOUNDS: {idx}") - return - - if idx not in self._by_bin: - self._by_bin[idx] = SortedList(key=lambda obs: obs.timestamp) - - # add to both lookup structures - _bin: SortedList = self._by_bin[idx] - _bin.add(observation) - self._by_time.add(observation) - - # manage within-bin forgetting - while len(_bin) > self.bin_buffer_length: - old = _bin.pop(0) - self._by_time.remove(old) - - # manage across-bin forgetting - if self.forget_min_observations is None or self.forget_min_time is None: - return - - while self.count() > self.forget_min_observations: - oldest_age = observation.timestamp - self._by_time[0].timestamp - if oldest_age < self.forget_min_time: - break - - # forget oldest entry - old = self._by_time.pop(0) - idx = self._get_bin(old) - _bin = self._by_bin[idx] - _bin.remove(old) - # make sure to remove bin if empty for bin-counting to work - if len(_bin) == 0: - self._by_bin.pop(idx) - - @property - def observations(self) -> Sequence[Observation]: - return list(self._by_time) - - def clear(self): - self._by_time.clear() - self._by_bin.clear() - - def count(self) -> int: - return len(self._by_time) - - def get_bin_counts(self) -> np.ndarray: - dense_1d = np.zeros((self.w * self.h,)) - for idx, _bin in self._by_bin.items(): - dense_1d[idx] = len(_bin) - return np.reshape(dense_1d, (self.w, self.h)) - - def _get_bin(self, observation: Observation) -> int: - x, y = ( - floor((ellipse_center + resolution / 2) / self.pixels_per_bin) - for ellipse_center, resolution in zip( - observation.ellipse.center, self.camera.resolution - ) - ) - # convert to 1D bin index - return x + y * self.h diff --git a/EyeTrackApp/pye3dcustom/refraction.py b/EyeTrackApp/pye3dcustom/refraction.py deleted file mode 100644 index 75045e6..0000000 --- a/EyeTrackApp/pye3dcustom/refraction.py +++ /dev/null @@ -1,141 +0,0 @@ -import itertools -from pathlib import Path -from .cpp.refraction_correction import apply_correction_pipeline - -import numpy as np -import msgpack - -LOAD_DIR = Path(__file__).parent / "refraction_models" -LOAD_VERSION = 1 - - -class ModelDeserializationError(Exception): - pass - - -class Refractionizer: - def __init__(self, degree=3, type_="default", custom_load_dir=None): - self.pipeline_radius_as_list = self.load_config_from_msgpack( - "radius", type_, degree, custom_load_dir - ) - - self.pipeline_gaze_vector_as_list = self.load_config_from_msgpack( - "gaze_vector", type_, degree, custom_load_dir - ) - - self.pipeline_sphere_center_as_list = self.load_config_from_msgpack( - "sphere_center", type_, degree, custom_load_dir - ) - - self.pipeline_pupil_circle_as_list = self.load_config_from_msgpack( - "pupil_circle", type_, degree, custom_load_dir - ) - - @staticmethod - def load_config_from_msgpack(feature, type_, degree, custom_load_dir=None): - load_dir = Path(custom_load_dir or LOAD_DIR).resolve() - name = f"{type_}_refraction_model_{feature}_degree_{degree}.msgpack" - path = load_dir / name - with path.open("rb") as file: - config_model = msgpack.unpack(file) - Refractionizer._validate_loaded_model_config(config_model) - try: - return list( - itertools.chain( - Refractionizer._polynomial_features_from_config(config_model), - Refractionizer._standard_scaler_from_config(config_model), - Refractionizer._linear_regression_from_config(config_model), - ) - ) - except KeyError as err: - raise ModelDeserializationError from err - - @staticmethod - def _validate_loaded_model_config(config_model): - if not isinstance(config_model, dict) or "version" not in config_model: - raise ModelDeserializationError("Unrecognized format") - if config_model["version"] != LOAD_VERSION: - raise ModelDeserializationError( - f"Unexpected version `{config_model['version']}` " - f"(expected `{LOAD_VERSION}``)" - ) - - @staticmethod - def _polynomial_features_from_config(config_model): - yield np.array(config_model["steps"]["PolynomialFeatures"]["powers"]) - - @staticmethod - def _standard_scaler_from_config(config_model): - config_scaler = config_model["steps"]["StandardScaler"] - yield np.array(config_scaler["mean"]) - yield np.array(config_scaler["var"]) - - @staticmethod - def _linear_regression_from_config(config_model): - config_lin_reg = config_model["steps"]["LinearRegression"] - yield np.array(config_lin_reg["coef"]) - yield np.array(config_lin_reg["intercept"]) - - @staticmethod - def _apply_correction_pipeline(X, pipeline_arrays): - return apply_correction_pipeline(np.asarray(X).T, *pipeline_arrays) - - def correct_radius(self, X): - return self._apply_correction_pipeline(X, self.pipeline_radius_as_list) - - def correct_gaze_vector(self, X): - return self._apply_correction_pipeline(X, self.pipeline_gaze_vector_as_list) - - def correct_sphere_center(self, X): - return self._apply_correction_pipeline(X, self.pipeline_sphere_center_as_list) - - def correct_pupil_circle(self, X): - return self._apply_correction_pipeline(X, self.pipeline_pupil_circle_as_list) - - -class SklearnRefractionizer(Refractionizer): - def __init__(self, degree=3, type_="default", custom_load_dir=None): - self.correct_radius = self.load_predict_fn_from_joblib_pickle( - "radius", type_, degree, custom_load_dir - ) - - self.correct_gaze_vector = self.load_predict_fn_from_joblib_pickle( - "gaze_vector", type_, degree, custom_load_dir - ) - - self.correct_sphere_center = self.load_predict_fn_from_joblib_pickle( - "sphere_center", type_, degree, custom_load_dir - ) - - self.correct_pupil_circle = self.load_predict_fn_from_joblib_pickle( - "pupil_circle", type_, degree, custom_load_dir - ) - - @staticmethod - def load_predict_fn_from_joblib_pickle( - feature, type_, degree, custom_load_dir=None - ): - import joblib - - load_dir = Path(custom_load_dir or LOAD_DIR).resolve() - name = f"{type_}_refraction_model_{feature}_degree_{degree}.save" - path = load_dir / name - try: - pipeline = joblib.load(path) - except FileNotFoundError as err: - raise - except Exception as exc: - raise ModelDeserializationError( - f"Failed to load pickled model from {path}" - ) from exc - return pipeline.predict - - -if __name__ == "__main__": - - refractionizer = Refractionizer() - - print(refractionizer.correct_sphere_center([[0.0, 0.0, 35.0]])) - print(refractionizer.correct_radius([[0.0, 0.0, 35.0, 0.0, 0.0, -1.0, 2.0]])) - print(refractionizer.correct_gaze_vector([[0.0, 0.0, 35.0, 0.0, 0.0, -1.0, 2.0]])) - print(refractionizer.correct_pupil_circle([[0.0, 0.0, 35.0, 0.0, 0.0, -1.0, 2.0]])) diff --git a/EyeTrackApp/pye3dcustom/refraction_models/default_refraction_model_gaze_vector_degree_3.msgpack b/EyeTrackApp/pye3dcustom/refraction_models/default_refraction_model_gaze_vector_degree_3.msgpack deleted file mode 100644 index 8aa76ddf6c7cfc9a4fca5a2fcb3171410163b82c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13522 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 diff --git a/EyeTrackApp/requirements.txt b/EyeTrackApp/requirements.txt deleted file mode 100644 index 17840cf..0000000 --- a/EyeTrackApp/requirements.txt +++ /dev/null @@ -1,33 +0,0 @@ -altgraph==0.17.2 -certifi==2022.6.15 -charset-normalizer==2.0.12 -comtypes==1.1.11 -dacite==1.6.0 -dataclasses==0.8 -docopt==0.6.2 -future==0.18.2 -idna==3.3 -importlib-metadata==4.8.3 -joblib==1.1.0 -msgpack==1.0.4 -numpy==1.19.5 -opencv-python==4.5.3.56 -pefile==2022.5.30 -pipreqs==0.4.11 -pyinstaller==4.10 -pyinstaller-hooks-contrib==2022.0 -pypiwin32==223 -PySimpleGUI==4.60.1 -python-osc==1.8.0 -pyttsx3==2.90 -pywin32==304 -pywin32-ctypes==0.2.0 -requests==2.27.1 -sortedcontainers==2.4.0 -typing_extensions==4.1.1 -urllib3==1.26.9 -yarg==0.1.9 -zipp==3.6.0 -python-osc==1.8.0 -sympy==1.2 -scipy==1.5.4 diff --git a/poetry.lock b/poetry.lock index f32f6d7..dc0565a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,21 +8,17 @@ python-versions = "*" [[package]] name = "black" -version = "22.8.0" +version = "22.10.0" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7" [package.dependencies] click = ">=8.0.0" -dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -40,56 +36,33 @@ python-versions = ">=3.6" [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "2.1.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = ">=3.5.0" +python-versions = ">=3.6.0" [package.extras] -unicode_backport = ["unicodedata2"] +unicode-backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.4" +version = "8.1.3" description = "Composable command line interface toolkit" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "dacite" -version = "1.6.0" -description = "Simple creation of data classes from dictionaries." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -dataclasses = {version = "*", markers = "python_version < \"3.7\""} - -[package.extras] -dev = ["black", "coveralls", "mypy", "pylint", "pytest (>=5)", "pytest-cov"] - -[[package]] -name = "dataclasses" -version = "0.8" -description = "A backport of the dataclasses module for Python 3.6" -category = "main" -optional = false -python-versions = ">=3.6, <3.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" [[package]] name = "flake8" @@ -100,7 +73,6 @@ optional = false python-versions = ">=3.6.1" [package.dependencies] -importlib-metadata = {version = ">=1.1.0,<4.3", markers = "python_version < \"3.8\""} mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.9.0,<2.10.0" pyflakes = ">=2.5.0,<2.6.0" @@ -121,22 +93,6 @@ category = "main" optional = false python-versions = ">=3.5" -[[package]] -name = "importlib-metadata" -version = "4.2.0" -description = "Read metadata from Python packages" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", "pyfakefs", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] - [[package]] name = "macholib" version = "1.16.2" @@ -186,34 +142,35 @@ python-versions = "*" [[package]] name = "numpy" -version = "1.19.5" +version = "1.23.4" description = "NumPy is the fundamental package for array computing with Python." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" [[package]] name = "opencv-python" -version = "4.5.3.56" +version = "4.6.0.66" description = "Wrapper package for OpenCV python bindings." category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -numpy = ">=1.13.3" - -[package.source] -type = "url" -url = "https://files.pythonhosted.org/packages/82/5e/f5df9ce92b7d25f43baf64327ea89f832f1eac7f250c1569a22f8b3fca3e/opencv_python-4.5.3.56-cp36-cp36m-win_amd64.whl" +numpy = [ + {version = ">=1.21.2", markers = "python_version >= \"3.10\" or python_version >= \"3.6\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""}, + {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""}, + {version = ">=1.14.5", markers = "python_version >= \"3.7\""}, + {version = ">=1.17.3", markers = "python_version >= \"3.8\""}, +] [[package]] name = "pathspec" -version = "0.9.0" +version = "0.10.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.7" [[package]] name = "pefile" @@ -228,14 +185,14 @@ future = "*" [[package]] name = "platformdirs" -version = "2.4.0" +version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] [[package]] @@ -246,6 +203,41 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "pydantic" +version = "1.10.2" +description = "Data validation and settings management using python type hints" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +typing-extensions = ">=4.1.0" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pye3d" +version = "0.3.1.post1" +description = "3D eye model" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +msgpack = ">=1" +numpy = "*" +sortedcontainers = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx (<4.4)"] +examples = ["opencv-python", "pupil-detectors"] +legacy-sklearn-models = ["joblib", "scikit-learn"] +testing = ["matplotlib", "opencv-python-headless", "pandas", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "scikit-image"] +with-opencv = ["opencv-python"] + [[package]] name = "pyflakes" version = "2.5.0" @@ -256,31 +248,31 @@ python-versions = ">=3.6" [[package]] name = "pyinstaller" -version = "4.10" +version = "5.6.2" description = "PyInstaller bundles a Python application and all its dependencies into a single package." category = "dev" optional = false -python-versions = "<3.11,>=3.6" +python-versions = "<3.12,>=3.7" [package.dependencies] altgraph = "*" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} -pefile = {version = ">=2017.8.1", markers = "sys_platform == \"win32\""} -pyinstaller-hooks-contrib = ">=2020.6" +pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""} +pyinstaller-hooks-contrib = ">=2021.4" pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +setuptools = "*" [package.extras] encryption = ["tinyaes (>=1.0.0)"] -hook_testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] +hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2022.0" +version = "2022.11" description = "Community maintained hooks for PyInstaller" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" [[package]] name = "pysimplegui" @@ -298,14 +290,6 @@ category = "main" optional = false python-versions = "*" -[[package]] -name = "pywin32" -version = "304" -description = "Python for Window Extensions" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "pywin32-ctypes" version = "0.2.0" @@ -316,32 +300,50 @@ python-versions = "*" [[package]] name = "requests" -version = "2.27.1" +version = "2.28.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7, <4" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" [package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "scipy" -version = "1.5.4" -description = "SciPy: Scientific Library for Python" +version = "1.9.3" +description = "Fundamental algorithms for scientific computing in Python" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" [package.dependencies] -numpy = ">=1.14.5" +numpy = ">=1.18.5,<1.26.0" + +[package.extras] +dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] +test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "setuptools" +version = "65.5.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "sortedcontainers" @@ -353,38 +355,22 @@ python-versions = "*" [[package]] name = "sympy" -version = "1.9" +version = "1.11.1" description = "Computer algebra system (CAS) in Python" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" [package.dependencies] mpmath = ">=0.19" -[[package]] -name = "tomli" -version = "1.2.3" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "typed-ast" -version = "1.5.4" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = ">=3.6" - [[package]] name = "typing-extensions" -version = "4.1.1" -description = "Backported and Experimental Type Hints for Python 3.6+" -category = "dev" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "urllib3" @@ -399,22 +385,10 @@ brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] -[[package]] -name = "zipp" -version = "3.6.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] -testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] - [metadata] lock-version = "1.1" -python-versions = "~3.6.2" -content-hash = "e09c41c346cca409c97844891b2c3c2294a6a36949efcdab558b7222ffe46619" +python-versions = "~3.11.0" +content-hash = "b59a104524f78b3dfc170751db515428495204063e9ebf448cd839eab4a3d8af" [metadata.files] altgraph = [ @@ -422,53 +396,43 @@ altgraph = [ {file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"}, ] black = [ - {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, - {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, - {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, - {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, - {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, - {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, - {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, - {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, - {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, - {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, - {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, - {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, - {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, - {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, - {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, - {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, - {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, - {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, - {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, + {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, + {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, + {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, + {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, + {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, + {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, + {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, + {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, + {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, + {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, + {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, + {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, + {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, + {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, + {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, + {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, + {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, + {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, + {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, + {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, + {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, ] certifi = [ {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] click = [ - {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, - {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -dacite = [ - {file = "dacite-1.6.0-py3-none-any.whl", hash = "sha256:4331535f7aabb505c732fa4c3c094313fc0a1d5ea19907bf4726a7819a68b93f"}, - {file = "dacite-1.6.0.tar.gz", hash = "sha256:d48125ed0a0352d3de9f493bf980038088f45f3f9d7498f090b50a847daaa6df"}, -] -dataclasses = [ - {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, - {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] flake8 = [ {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, @@ -481,10 +445,6 @@ idna = [ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] -importlib-metadata = [ - {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, - {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, -] macholib = [ {file = "macholib-1.16.2-py2.py3-none-any.whl", hash = "sha256:44c40f2cd7d6726af8fa6fe22549178d3a4dfecc35a9cd15ea916d9c83a688e0"}, {file = "macholib-1.16.2.tar.gz", hash = "sha256:557bbfa1bb255c20e9abafe7ed6cd8046b48d9525db2f9b77d3122a63a2a8bf8"}, @@ -556,77 +516,138 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] numpy = [ - {file = "numpy-1.19.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc6bd4fd593cb261332568485e20a0712883cf631f6f5e8e86a52caa8b2b50ff"}, - {file = "numpy-1.19.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aeb9ed923be74e659984e321f609b9ba54a48354bfd168d21a2b072ed1e833ea"}, - {file = "numpy-1.19.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8b5e972b43c8fc27d56550b4120fe6257fdc15f9301914380b27f74856299fea"}, - {file = "numpy-1.19.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:43d4c81d5ffdff6bae58d66a3cd7f54a7acd9a0e7b18d97abb255defc09e3140"}, - {file = "numpy-1.19.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a4646724fba402aa7504cd48b4b50e783296b5e10a524c7a6da62e4a8ac9698d"}, - {file = "numpy-1.19.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:2e55195bc1c6b705bfd8ad6f288b38b11b1af32f3c8289d6c50d47f950c12e76"}, - {file = "numpy-1.19.5-cp36-cp36m-win32.whl", hash = "sha256:39b70c19ec771805081578cc936bbe95336798b7edf4732ed102e7a43ec5c07a"}, - {file = "numpy-1.19.5-cp36-cp36m-win_amd64.whl", hash = "sha256:dbd18bcf4889b720ba13a27ec2f2aac1981bd41203b3a3b27ba7a33f88ae4827"}, - {file = "numpy-1.19.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:603aa0706be710eea8884af807b1b3bc9fb2e49b9f4da439e76000f3b3c6ff0f"}, - {file = "numpy-1.19.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cae865b1cae1ec2663d8ea56ef6ff185bad091a5e33ebbadd98de2cfa3fa668f"}, - {file = "numpy-1.19.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:36674959eed6957e61f11c912f71e78857a8d0604171dfd9ce9ad5cbf41c511c"}, - {file = "numpy-1.19.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:06fab248a088e439402141ea04f0fffb203723148f6ee791e9c75b3e9e82f080"}, - {file = "numpy-1.19.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6149a185cece5ee78d1d196938b2a8f9d09f5a5ebfbba66969302a778d5ddd1d"}, - {file = "numpy-1.19.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:50a4a0ad0111cc1b71fa32dedd05fa239f7fb5a43a40663269bb5dc7877cfd28"}, - {file = "numpy-1.19.5-cp37-cp37m-win32.whl", hash = "sha256:d051ec1c64b85ecc69531e1137bb9751c6830772ee5c1c426dbcfe98ef5788d7"}, - {file = "numpy-1.19.5-cp37-cp37m-win_amd64.whl", hash = "sha256:a12ff4c8ddfee61f90a1633a4c4afd3f7bcb32b11c52026c92a12e1325922d0d"}, - {file = "numpy-1.19.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf2402002d3d9f91c8b01e66fbb436a4ed01c6498fffed0e4c7566da1d40ee1e"}, - {file = "numpy-1.19.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1ded4fce9cfaaf24e7a0ab51b7a87be9038ea1ace7f34b841fe3b6894c721d1c"}, - {file = "numpy-1.19.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:012426a41bc9ab63bb158635aecccc7610e3eff5d31d1eb43bc099debc979d94"}, - {file = "numpy-1.19.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:759e4095edc3c1b3ac031f34d9459fa781777a93ccc633a472a5468587a190ff"}, - {file = "numpy-1.19.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a9d17f2be3b427fbb2bce61e596cf555d6f8a56c222bd2ca148baeeb5e5c783c"}, - {file = "numpy-1.19.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:99abf4f353c3d1a0c7a5f27699482c987cf663b1eac20db59b8c7b061eabd7fc"}, - {file = "numpy-1.19.5-cp38-cp38-win32.whl", hash = "sha256:384ec0463d1c2671170901994aeb6dce126de0a95ccc3976c43b0038a37329c2"}, - {file = "numpy-1.19.5-cp38-cp38-win_amd64.whl", hash = "sha256:811daee36a58dc79cf3d8bdd4a490e4277d0e4b7d103a001a4e73ddb48e7e6aa"}, - {file = "numpy-1.19.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c843b3f50d1ab7361ca4f0b3639bf691569493a56808a0b0c54a051d260b7dbd"}, - {file = "numpy-1.19.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d6631f2e867676b13026e2846180e2c13c1e11289d67da08d71cacb2cd93d4aa"}, - {file = "numpy-1.19.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7fb43004bce0ca31d8f13a6eb5e943fa73371381e53f7074ed21a4cb786c32f8"}, - {file = "numpy-1.19.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2ea52bd92ab9f768cc64a4c3ef8f4b2580a17af0a5436f6126b08efbd1838371"}, - {file = "numpy-1.19.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:400580cbd3cff6ffa6293df2278c75aef2d58d8d93d3c5614cd67981dae68ceb"}, - {file = "numpy-1.19.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:df609c82f18c5b9f6cb97271f03315ff0dbe481a2a02e56aeb1b1a985ce38e60"}, - {file = "numpy-1.19.5-cp39-cp39-win32.whl", hash = "sha256:ab83f24d5c52d60dbc8cd0528759532736b56db58adaa7b5f1f76ad551416a1e"}, - {file = "numpy-1.19.5-cp39-cp39-win_amd64.whl", hash = "sha256:0eef32ca3132a48e43f6a0f5a82cb508f22ce5a3d6f67a8329c81c8e226d3f6e"}, - {file = "numpy-1.19.5-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:a0d53e51a6cb6f0d9082decb7a4cb6dfb33055308c4c44f53103c073f649af73"}, - {file = "numpy-1.19.5.zip", hash = "sha256:a76f502430dd98d7546e1ea2250a7360c065a5fdea52b2dffe8ae7180909b6f4"}, + {file = "numpy-1.23.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:95d79ada05005f6f4f337d3bb9de8a7774f259341c70bc88047a1f7b96a4bcb2"}, + {file = "numpy-1.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:926db372bc4ac1edf81cfb6c59e2a881606b409ddc0d0920b988174b2e2a767f"}, + {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c237129f0e732885c9a6076a537e974160482eab8f10db6292e92154d4c67d71"}, + {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8365b942f9c1a7d0f0dc974747d99dd0a0cdfc5949a33119caf05cb314682d3"}, + {file = "numpy-1.23.4-cp310-cp310-win32.whl", hash = "sha256:2341f4ab6dba0834b685cce16dad5f9b6606ea8a00e6da154f5dbded70fdc4dd"}, + {file = "numpy-1.23.4-cp310-cp310-win_amd64.whl", hash = "sha256:d331afac87c92373826af83d2b2b435f57b17a5c74e6268b79355b970626e329"}, + {file = "numpy-1.23.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:488a66cb667359534bc70028d653ba1cf307bae88eab5929cd707c761ff037db"}, + {file = "numpy-1.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce03305dd694c4873b9429274fd41fc7eb4e0e4dea07e0af97a933b079a5814f"}, + {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8981d9b5619569899666170c7c9748920f4a5005bf79c72c07d08c8a035757b0"}, + {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a70a7d3ce4c0e9284e92285cba91a4a3f5214d87ee0e95928f3614a256a1488"}, + {file = "numpy-1.23.4-cp311-cp311-win32.whl", hash = "sha256:5e13030f8793e9ee42f9c7d5777465a560eb78fa7e11b1c053427f2ccab90c79"}, + {file = "numpy-1.23.4-cp311-cp311-win_amd64.whl", hash = "sha256:7607b598217745cc40f751da38ffd03512d33ec06f3523fb0b5f82e09f6f676d"}, + {file = "numpy-1.23.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ab46e4e7ec63c8a5e6dbf5c1b9e1c92ba23a7ebecc86c336cb7bf3bd2fb10e5"}, + {file = "numpy-1.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8aae2fb3180940011b4862b2dd3756616841c53db9734b27bb93813cd79fce6"}, + {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c053d7557a8f022ec823196d242464b6955a7e7e5015b719e76003f63f82d0f"}, + {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0882323e0ca4245eb0a3d0a74f88ce581cc33aedcfa396e415e5bba7bf05f68"}, + {file = "numpy-1.23.4-cp38-cp38-win32.whl", hash = "sha256:dada341ebb79619fe00a291185bba370c9803b1e1d7051610e01ed809ef3a4ba"}, + {file = "numpy-1.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:0fe563fc8ed9dc4474cbf70742673fc4391d70f4363f917599a7fa99f042d5a8"}, + {file = "numpy-1.23.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c67b833dbccefe97cdd3f52798d430b9d3430396af7cdb2a0c32954c3ef73894"}, + {file = "numpy-1.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f76025acc8e2114bb664294a07ede0727aa75d63a06d2fae96bf29a81747e4a7"}, + {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12ac457b63ec8ded85d85c1e17d85efd3c2b0967ca39560b307a35a6703a4735"}, + {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95de7dc7dc47a312f6feddd3da2500826defdccbc41608d0031276a24181a2c0"}, + {file = "numpy-1.23.4-cp39-cp39-win32.whl", hash = "sha256:f2f390aa4da44454db40a1f0201401f9036e8d578a25f01a6e237cea238337ef"}, + {file = "numpy-1.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:f260da502d7441a45695199b4e7fd8ca87db659ba1c78f2bbf31f934fe76ae0e"}, + {file = "numpy-1.23.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61be02e3bf810b60ab74e81d6d0d36246dbfb644a462458bb53b595791251911"}, + {file = "numpy-1.23.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:296d17aed51161dbad3c67ed6d164e51fcd18dbcd5dd4f9d0a9c6055dce30810"}, + {file = "numpy-1.23.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4d52914c88b4930dafb6c48ba5115a96cbab40f45740239d9f4159c4ba779962"}, + {file = "numpy-1.23.4.tar.gz", hash = "sha256:ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c"}, +] +opencv-python = [ + {file = "opencv-python-4.6.0.66.tar.gz", hash = "sha256:c5bfae41ad4031e66bb10ec4a0a2ffd3e514d092652781e8b1ac98d1b59f1158"}, + {file = "opencv_python-4.6.0.66-cp36-abi3-macosx_10_15_x86_64.whl", hash = "sha256:e6e448b62afc95c5b58f97e87ef84699e6607fe5c58730a03301c52496005cae"}, + {file = "opencv_python-4.6.0.66-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af8ba35a4fcb8913ffb86e92403e9a656a4bff4a645d196987468f0f8947875"}, + {file = "opencv_python-4.6.0.66-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbdc84a9b4ea2cbae33861652d25093944b9959279200b7ae0badd32439f74de"}, + {file = "opencv_python-4.6.0.66-cp36-abi3-win32.whl", hash = "sha256:f482e78de6e7b0b060ff994ffd859bddc3f7f382bb2019ef157b0ea8ca8712f5"}, + {file = "opencv_python-4.6.0.66-cp36-abi3-win_amd64.whl", hash = "sha256:0dc82a3d8630c099d2f3ac1b1aabee164e8188db54a786abb7a4e27eba309440"}, + {file = "opencv_python-4.6.0.66-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:6e32af22e3202748bd233ed8f538741876191863882eba44e332d1a34993165b"}, ] -opencv-python = [] pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, + {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, + {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, ] pefile = [ {file = "pefile-2022.5.30.tar.gz", hash = "sha256:a5488a3dd1fd021ce33f969780b88fe0f7eebb76eb20996d7318f307612a045b"}, ] platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] pycodestyle = [ {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, ] +pydantic = [ + {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, + {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, + {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, + {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, + {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, + {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, + {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, + {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, + {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, +] +pye3d = [ + {file = "pye3d-0.3.1.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae6f745f4f66e9fe74986cf41c13135e5e368f8987aeff73c60fa25c29c39264"}, + {file = "pye3d-0.3.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:491d78bb7cae56d6746fc5cdac7d4d8b67a098583182fb37442818b6afa1743f"}, + {file = "pye3d-0.3.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:9779822129b372102a89b9c275803f299dbe9a8323350c5f5b41a2fe251b1714"}, + {file = "pye3d-0.3.1.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bfddec99fc3fad36115ed271b810161a98677807acac315fe84713a0ab5cd1b4"}, + {file = "pye3d-0.3.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa9d5cb2e68c41d44faeaee3390b36c2011dcc27c6395a078ba68dace5ab06d"}, + {file = "pye3d-0.3.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:4ef8fd736c364a89dc86a30d76f74039ab5b7fe41e256284db94a464454d7127"}, + {file = "pye3d-0.3.1.post1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b4724cce86fb4dc2c763be460b51b6fd69eb6aa96650aca71e1b114a268fd24a"}, + {file = "pye3d-0.3.1.post1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7646fe9f2f0da0514a8169d12a403a91f3f309de219ea5b650a9d491dcf1a3f"}, + {file = "pye3d-0.3.1.post1-cp36-cp36m-win_amd64.whl", hash = "sha256:fc5b58b5d14ceb8717956c288cee1ed33fbe309b843af4e80428e236bf8813c4"}, + {file = "pye3d-0.3.1.post1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d2eb5ec4017b18921b5da8dafa311204c9b60a72d6cfbc758835d2b66dca47de"}, + {file = "pye3d-0.3.1.post1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2877b8c00d00e8e103dbe32d81f9c0f420bcc1ecfdd320df4e6e5ad2234782c"}, + {file = "pye3d-0.3.1.post1-cp37-cp37m-win_amd64.whl", hash = "sha256:eabf6341a48bd754106e827d984294cf10298d4f634ea2b63f70ede8011c1463"}, + {file = "pye3d-0.3.1.post1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:74230323b2f88a5bd60d57c4837863ccb4c0fe3d0a7305c130da038f13a65e9d"}, + {file = "pye3d-0.3.1.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96aadb0043b8c7561a8ed4e475d86021ae3c2725fe06c040f03d26180836562d"}, + {file = "pye3d-0.3.1.post1-cp38-cp38-win_amd64.whl", hash = "sha256:2e0df8810205347c5b9136803010691fb7f4b90b1860a2535a742feadd804fc6"}, + {file = "pye3d-0.3.1.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17e2b093fd567a448f3daa8ebe6b5aaf863738b34557b27a6f01e2070da8c66f"}, + {file = "pye3d-0.3.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36f473cf7ab3ca94bf91ba6aa2f1c44305164850e754adc35f43f7c4d61639ce"}, + {file = "pye3d-0.3.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:b7953b879f7e2c3c132b047ddb7653deb07ee00573a47adc9f703feb02e606b0"}, + {file = "pye3d-0.3.1.post1.tar.gz", hash = "sha256:3258b2f545712927af7c47a5d27639dfeb7d5936cf1604c54d6cced526581c91"}, +] pyflakes = [ {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, ] pyinstaller = [ - {file = "pyinstaller-4.10-py3-none-macosx_10_13_universal2.whl", hash = "sha256:15557cd1a79d182967f0a5040750e6902e13ebd6cab41e3ed84d7b28a306357b"}, - {file = "pyinstaller-4.10-py3-none-manylinux2014_aarch64.whl", hash = "sha256:f2166ff2cd95eefb0d377ae8d1071f186fa25edd410ede65b376162d5ec41909"}, - {file = "pyinstaller-4.10-py3-none-manylinux2014_i686.whl", hash = "sha256:7d94518ba1f8e9a8577345312276891ad7d6cd9785e453e9951b35647e2c7078"}, - {file = "pyinstaller-4.10-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:70c71e827f4b34602cbc7a0947a067b662c1cbdc4db51832e13b97cca3c54dd7"}, - {file = "pyinstaller-4.10-py3-none-manylinux2014_s390x.whl", hash = "sha256:05c21117b84199272ebd355b556af4714f6e79245e1c435d6f16653786d7d17e"}, - {file = "pyinstaller-4.10-py3-none-manylinux2014_x86_64.whl", hash = "sha256:714c4dcc319a41416744d1e30c6317405dfaed80d2adc45f8bfa70dc7367e664"}, - {file = "pyinstaller-4.10-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:581620bdcd32f01e89b13231256b807bb090e7eadf40c81c864ec402afa4758a"}, - {file = "pyinstaller-4.10-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d4f79c0a774451f12baca4e476376418f011fa3039dde8fd172ea2aa8ff67bad"}, - {file = "pyinstaller-4.10-py3-none-win32.whl", hash = "sha256:cfed0b3a43e73550a43a094610328109564710b9514afa093ef7199d072cae87"}, - {file = "pyinstaller-4.10-py3-none-win_amd64.whl", hash = "sha256:0dcaf6557cdb2da763c46e06e95a94a7634ab03fb09d91bc77988b01ee05c907"}, - {file = "pyinstaller-4.10.tar.gz", hash = "sha256:7749c868d2e2dc84df7d6f65437226183c8a366f3a99bb2737785625c3a3cca1"}, + {file = "pyinstaller-5.6.2-py3-none-macosx_10_13_universal2.whl", hash = "sha256:1b1e3b37a22fb36555d917f0c3dfb998159ff4af6d8fa7cc0074d630c6fe81ad"}, + {file = "pyinstaller-5.6.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:05df5d2b9ca645cc6ef61d8a85451d2aabe5501997f1f50cd94306fd6bc0485d"}, + {file = "pyinstaller-5.6.2-py3-none-manylinux2014_i686.whl", hash = "sha256:eb083c25f711769af0898852ea30dcb727ba43990bbdf9ffbaa9c77a7bd0d720"}, + {file = "pyinstaller-5.6.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0d167d57036219914188f1400427dd297b975707e78c32a5511191e607be920a"}, + {file = "pyinstaller-5.6.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:32727232f446aa96e394f01b0c35b3de0dc3513c6ba3e26d1ef64c57edb1e9e5"}, + {file = "pyinstaller-5.6.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:181856ade585b090379ae26b7017dc2c30620e36e3a804b381417a6dc3b2a82b"}, + {file = "pyinstaller-5.6.2-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:77888f52b61089caa0bee70809bbce9e9b1c613c88b6cb0742ff2a45f1511cbb"}, + {file = "pyinstaller-5.6.2-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d888db9afedff290d362ee296d30eb339abeba707ca1565916ce1cd5947131c3"}, + {file = "pyinstaller-5.6.2-py3-none-win32.whl", hash = "sha256:e026adc92c60158741d0bfca27eefaa2414801f61328cb84d0c88241fe8c2087"}, + {file = "pyinstaller-5.6.2-py3-none-win_amd64.whl", hash = "sha256:04ecf805bde2ef25b8e3642410871e6747c22fa7254107f155b8cd179c2a13b6"}, + {file = "pyinstaller-5.6.2.tar.gz", hash = "sha256:865025b6809d777bb0f66d8f8ab50cc97dc3dbe0ff09a1ef1f2fd646432714fc"}, ] pyinstaller-hooks-contrib = [ - {file = "pyinstaller-hooks-contrib-2022.0.tar.gz", hash = "sha256:61b667f51b2525377fae30793f38fd9752a08032c72b209effabf707c840cc38"}, - {file = "pyinstaller_hooks_contrib-2022.0-py2.py3-none-any.whl", hash = "sha256:29f0bd8fbb2ff6f2df60a0c147e5b5ad65ae5c1a982d90641a5f712de03fa161"}, + {file = "pyinstaller-hooks-contrib-2022.11.tar.gz", hash = "sha256:2e1870350bb9ef2e09c1c1bb30347eb3185c5ef38c040ed04190d6d0b4b5df62"}, + {file = "pyinstaller_hooks_contrib-2022.11-py2.py3-none-any.whl", hash = "sha256:8db4064d9c127940455ec363bebbf74228be21cdafb44f7ea4f44cf434d9bcaa"}, ] pysimplegui = [ {file = "PySimpleGUI-4.60.4-py3-none-any.whl", hash = "sha256:e133fbd21779f0f125cebbc2a4e1f5a931a383738661013ff33ad525d5611eda"}, @@ -636,104 +657,54 @@ python-osc = [ {file = "python-osc-1.8.0.tar.gz", hash = "sha256:2f8c187c68d239960fb2eddcb5346a62a9b35e64f2de045b3e5e509f475ca73d"}, {file = "python_osc-1.8.0-py3-none-any.whl", hash = "sha256:9e2abb2fc9ba2c356f8e951609a03c9c7017bf0bad82cca8490e9b8af9e92a0b"}, ] -pywin32 = [ - {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"}, - {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"}, - {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"}, - {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"}, - {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"}, - {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"}, - {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"}, - {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"}, - {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"}, - {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"}, - {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"}, - {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"}, - {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"}, - {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"}, -] pywin32-ctypes = [ {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, ] requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, ] scipy = [ - {file = "scipy-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4f12d13ffbc16e988fa40809cbbd7a8b45bc05ff6ea0ba8e3e41f6f4db3a9e47"}, - {file = "scipy-1.5.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a254b98dbcc744c723a838c03b74a8a34c0558c9ac5c86d5561703362231107d"}, - {file = "scipy-1.5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:368c0f69f93186309e1b4beb8e26d51dd6f5010b79264c0f1e9ca00cd92ea8c9"}, - {file = "scipy-1.5.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4598cf03136067000855d6b44d7a1f4f46994164bcd450fb2c3d481afc25dd06"}, - {file = "scipy-1.5.4-cp36-cp36m-win32.whl", hash = "sha256:e98d49a5717369d8241d6cf33ecb0ca72deee392414118198a8e5b4c35c56340"}, - {file = "scipy-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:65923bc3809524e46fb7eb4d6346552cbb6a1ffc41be748535aa502a2e3d3389"}, - {file = "scipy-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9ad4fcddcbf5dc67619379782e6aeef41218a79e17979aaed01ed099876c0e62"}, - {file = "scipy-1.5.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f87b39f4d69cf7d7529d7b1098cb712033b17ea7714aed831b95628f483fd012"}, - {file = "scipy-1.5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:25b241034215247481f53355e05f9e25462682b13bd9191359075682adcd9554"}, - {file = "scipy-1.5.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:fa789583fc94a7689b45834453fec095245c7e69c58561dc159b5d5277057e4c"}, - {file = "scipy-1.5.4-cp37-cp37m-win32.whl", hash = "sha256:d6d25c41a009e3c6b7e757338948d0076ee1dd1770d1c09ec131f11946883c54"}, - {file = "scipy-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:2c872de0c69ed20fb1a9b9cf6f77298b04a26f0b8720a5457be08be254366c6e"}, - {file = "scipy-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e360cb2299028d0b0d0f65a5c5e51fc16a335f1603aa2357c25766c8dab56938"}, - {file = "scipy-1.5.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3397c129b479846d7eaa18f999369a24322d008fac0782e7828fa567358c36ce"}, - {file = "scipy-1.5.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:168c45c0c32e23f613db7c9e4e780bc61982d71dcd406ead746c7c7c2f2004ce"}, - {file = "scipy-1.5.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:213bc59191da2f479984ad4ec39406bf949a99aba70e9237b916ce7547b6ef42"}, - {file = "scipy-1.5.4-cp38-cp38-win32.whl", hash = "sha256:634568a3018bc16a83cda28d4f7aed0d803dd5618facb36e977e53b2df868443"}, - {file = "scipy-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:b03c4338d6d3d299e8ca494194c0ae4f611548da59e3c038813f1a43976cb437"}, - {file = "scipy-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3d5db5d815370c28d938cf9b0809dade4acf7aba57eaf7ef733bfedc9b2474c4"}, - {file = "scipy-1.5.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b0ceb23560f46dd236a8ad4378fc40bad1783e997604ba845e131d6c680963e"}, - {file = "scipy-1.5.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:ed572470af2438b526ea574ff8f05e7f39b44ac37f712105e57fc4d53a6fb660"}, - {file = "scipy-1.5.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8c8d6ca19c8497344b810b0b0344f8375af5f6bb9c98bd42e33f747417ab3f57"}, - {file = "scipy-1.5.4-cp39-cp39-win32.whl", hash = "sha256:d84cadd7d7998433334c99fa55bcba0d8b4aeff0edb123b2a1dfcface538e474"}, - {file = "scipy-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:cc1f78ebc982cd0602c9a7615d878396bec94908db67d4ecddca864d049112f2"}, - {file = "scipy-1.5.4.tar.gz", hash = "sha256:4a453d5e5689de62e5d38edf40af3f17560bfd63c9c5bd228c18c1f99afa155b"}, + {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, + {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, + {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, + {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, + {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, + {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, + {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, +] +setuptools = [ + {file = "setuptools-65.5.0-py3-none-any.whl", hash = "sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356"}, + {file = "setuptools-65.5.0.tar.gz", hash = "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17"}, ] sortedcontainers = [ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] sympy = [ - {file = "sympy-1.9-py3-none-any.whl", hash = "sha256:8bc5de4608b7aa4e7ffd1b25452ae87ccc5f6ca667c661aafb854a1ade337d0c"}, - {file = "sympy-1.9.tar.gz", hash = "sha256:c7a880e229df96759f955d4f3970d4cabce79f60f5b18830c08b90ce77cd5fdc"}, -] -tomli = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] -typed-ast = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, + {file = "sympy-1.11.1-py3-none-any.whl", hash = "sha256:938f984ee2b1e8eae8a07b884c8b7a1146010040fccddc6539c54f401c8f6fcf"}, + {file = "sympy-1.11.1.tar.gz", hash = "sha256:e32380dce63cb7c0108ed525570092fd45168bdae2faa17e528221ef72e88658"}, ] typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, ] urllib3 = [ {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, ] -zipp = [ - {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, - {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, -] diff --git a/pyproject.toml b/pyproject.toml index 9e0b82e..3a1a92c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,34 +7,20 @@ license = "MIT" repository = "https://github.com/RedHawk989/EyeTrackVR" [tool.poetry.dependencies] -python = "~3.6.2" -PySimpleGUI = "^4.60.4" -msgpack = "^1.0.4" +python = "~3.11.0" python-osc = "^1.8.0" -dacite = "^1.6.0" -pywin32 = "^304" -dataclasses = "^0.8" -numpy= "^1.19.5" -sortedcontainers = "^2.4.0" -sympy = "^1.9.0" -requests = "^2.27.1" -# for some reason OpenCV / numpy maintainers arent specifying dependencies correctly resulting in poetry throwing errors -# this isnt a good solution and i shouldnt need to do this because opencv 4.5.3.56 is compatible with python ^3.6.2 -# and numpy 1.19.5 but poetry has forced my hand, and since we are stuck on python 3.6 for now, this is the best solution -# we cant upgrade / downgrade numpy or opencv to resolve the errors because that breaks pyinstaller and a lot of other things -# this is really shitty and i fucking hate it because it means we have to specify the exact wheel to use per platform / architecture -# although this isnt a problem that poses any majour issues it is super annoying -# https://github.com/python-poetry/poetry/issues/4451#issuecomment-1200467157 -opencv-python = [ - {platform = "win32", markers="platform_machine=='AMD64'", url="https://files.pythonhosted.org/packages/82/5e/f5df9ce92b7d25f43baf64327ea89f832f1eac7f250c1569a22f8b3fca3e/opencv_python-4.5.3.56-cp36-cp36m-win_amd64.whl"}, - {platform = "win32", markers="platform_machine=='x86_64'", url="https://files.pythonhosted.org/packages/82/5e/f5df9ce92b7d25f43baf64327ea89f832f1eac7f250c1569a22f8b3fca3e/opencv_python-4.5.3.56-cp36-cp36m-win_amd64.whl"}, - {platform = "win32", markers="platform_machine=='x86'", url="https://files.pythonhosted.org/packages/0b/35/e1b4bd9003ff55ef176d172374629ac5f78533d473b75def07cb6313e467/opencv_python-4.5.3.56-cp36-cp36m-win32.whl"} -] -scipy = "^1.5.4" +opencv-python = "^4.6.0.66" +numpy = "^1.23.4" +pye3d = "^0.3.1.post1" +requests = "^2.28.1" +pysimplegui = "^4.60.4" +scipy = "^1.9.3" +pydantic = "^1.10.2" +sympy = "^1.11.1" -[tool.poetry.dev-dependencies] -black = "^22.8.0" -pyinstaller = "^4.10.0" +[tool.poetry.group.dev.dependencies] +black = "^22.10.0" +pyinstaller = "^5.6.2" flake8 = "^5.0.4" [build-system] From e4431dfaefae833970a4a603bb707517b8a9c73f Mon Sep 17 00:00:00 2001 From: Assassinsorrow <49711232+ShyAssassin@users.noreply.github.com> Date: Thu, 3 Nov 2022 22:27:17 +0200 Subject: [PATCH 2/2] Update eyetrackapp.py --- EyeTrackApp/eyetrackapp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EyeTrackApp/eyetrackapp.py b/EyeTrackApp/eyetrackapp.py index c17565a..3983cbf 100644 --- a/EyeTrackApp/eyetrackapp.py +++ b/EyeTrackApp/eyetrackapp.py @@ -34,7 +34,7 @@ def main(): # Check to see if we have an ROI. If not, bring up ROI finder GUI. # Spawn worker threads - osc_queue: queue.Queue[tuple[bool, int, int, int]] = queue.Queue() + osc_queue: queue.Queue[tuple[bool, int, int]] = queue.Queue() osc = VRChatOSC(cancellation_event, osc_queue, config) osc_thread = threading.Thread(target=osc.run) # start worker threads