diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 692abfe..4fe47f7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,12 +78,12 @@ jobs: #mv ./dist/ETVR ./dist/ETVR.bin run: | ls -a build - mv ./build/eyetrackapp ./build/eyetrackapp.bin + mv ./dist/eyetrackapp ./dist/eyetrackapp.bin - uses: actions/upload-artifact@v2 with: name: production-files - path: build + path: dist deploy: runs-on: ubuntu-latest name: Deploy diff --git a/.gitignore b/.gitignore index e0b4bfe..751f927 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,13 @@ **/*.pyc *.cfg *.log +EyeTrackApp/venv EyeTrackApp/eyetrack_settings.json EyeTrackApp/eyetrack_settings.backup EyeTrackApp/build EyeTrackApp/dist +build +dist EyeTrackApp/IBO_LEFT.png EyeTrackApp/IBO_RIGHT.png diff --git a/EyeTrackApp/algo_settings_widget.py b/EyeTrackApp/algo_settings_widget.py index f27be1f..e1d8942 100644 --- a/EyeTrackApp/algo_settings_widget.py +++ b/EyeTrackApp/algo_settings_widget.py @@ -65,7 +65,7 @@ class AlgoSettingsWidget: default=self.config.gui_HSRAC, key=self.gui_HSRAC, background_color='#424042', - tooltip="Our flagship algoritim, utilizing both HSF and RANSAC for best tracking quality and lighting resistance.", + tooltip="Our flagship algorithm, utilizing both HSF and RANSAC for best tracking quality and lighting resistance.", ), sg.Combo(['1', '2', '3', '4', '5', '6'], default_value=self.config.gui_HSRACP, @@ -74,7 +74,7 @@ class AlgoSettingsWidget: text_color='white', button_arrow_color="black", button_background_color="#6f4ca1", - tooltip="Select the priority of eyetracking algorithims.", + tooltip="Select the priority of eyetracking algorithms.", ), sg.Text("HSRAC", background_color='#424042'), # ], @@ -111,7 +111,7 @@ class AlgoSettingsWidget: text_color='white', button_arrow_color="black", button_background_color="#6f4ca1", - tooltip="Select the priority of eyetracking algorithims.", + tooltip="Select the priority of eyetracking algorithms.", ), sg.Text("DADDY", background_color='#424042'), # ], @@ -130,7 +130,7 @@ class AlgoSettingsWidget: text_color='white', button_arrow_color="black", button_background_color="#6f4ca1", - tooltip="Select the priority of eyetracking algorithims.", + tooltip="Select the priority of eyetracking algorithms.", ), sg.Text("RANSAC 3D", background_color='#424042'), ], @@ -149,7 +149,7 @@ class AlgoSettingsWidget: text_color='white', button_arrow_color="black", button_background_color="#6f4ca1", - tooltip="Select the priority of eyetracking algorithims.", + tooltip="Select the priority of eyetracking algorithms.", ), sg.Text("LEAP", background_color='#424042'), @@ -158,7 +158,7 @@ class AlgoSettingsWidget: default=self.config.gui_BLOB, key=self.gui_BLOB, background_color='#424042', - tooltip="Blob tracking is the oldest and worst tracking algorithm, it provides fast, though sometimes innaccurate tracking.", + tooltip="Blob tracking is the oldest and worst tracking algorithm, it provides fast, though sometimes inaccurate tracking.", ), sg.Combo(['1', '2', '3', '4', '5', '6'], default_value=self.config.gui_BLOBP, @@ -167,7 +167,7 @@ class AlgoSettingsWidget: text_color='white', button_arrow_color="black", button_background_color="#6f4ca1", - tooltip="Select the priority of eyetracking algorithims.", + tooltip="Select the priority of eyetracking algorithms.", ), sg.Text("Blob", background_color='#424042'), ], @@ -249,7 +249,7 @@ class AlgoSettingsWidget: orientation="h", key=self.gui_HSF_radius_left, background_color='#424042', - tooltip="Adjusts the radius paramater for HSF. Only adjust if you are having tracking issues.", + tooltip="Adjusts the radius parameter for HSF. Only adjust if you are having tracking issues.", ), sg.Text("Right HSF Radius:", background_color='#424042'), sg.Slider( @@ -258,7 +258,7 @@ class AlgoSettingsWidget: orientation="h", key=self.gui_HSF_radius_right, background_color='#424042', - tooltip="Adjusts the radius paramater for HSF. Only adjust if you are having tracking issues.", + tooltip="Adjusts the radius parameter for HSF. Only adjust if you are having tracking issues.", ), ], @@ -269,7 +269,7 @@ class AlgoSettingsWidget: orientation="h", key=self.gui_thresh_add, background_color='#424042', - tooltip="Adjusts the ammount of threshold to add to RANSAC. Usefull for fine tuning your setup.", + tooltip="Adjusts the amount of threshold to add to RANSAC. Useful for fine tuning your setup.", ), sg.Text("Blob Threshold", background_color='#424042'), # TODO make this for right and left eyes? I dont know how vital that is.. @@ -289,7 +289,7 @@ class AlgoSettingsWidget: orientation="h", key=self.gui_blob_minsize, background_color='#424042', - tooltip="Minimun size a blob has to be for blob tracking.", + tooltip="Minimum size a blob has to be for blob tracking.", ), sg.Text("Max Blob Size:", background_color='#424042'), diff --git a/EyeTrackApp/camera_widget.py b/EyeTrackApp/camera_widget.py index ef39016..c1f3937 100644 --- a/EyeTrackApp/camera_widget.py +++ b/EyeTrackApp/camera_widget.py @@ -10,10 +10,9 @@ from camera import Camera, CameraState from osc import EyeId import cv2 import sys -from utils.misc_utils import PlaySound,SND_FILENAME,SND_ASYNC +from utils.misc_utils import PlaySound,SND_FILENAME,SND_ASYNC, resource_path import traceback import numpy as np - class CameraWidget: def __init__(self, widget_id: EyeId, main_config: EyeTrackConfig, osc_queue: Queue): self.gui_camera_addr = f"-CAMERAADDR{widget_id}-" @@ -270,7 +269,7 @@ class CameraWidget: if event == self.gui_restart_calibration: self.ransac.calibration_frame_counter = self.settings.calibration_samples self.ransac.ibo.clear_filter() - PlaySound('Audio/start.wav', SND_FILENAME | SND_ASYNC) + PlaySound(resource_path('Audio/start.wav'), SND_FILENAME | SND_ASYNC) if event == self.gui_stop_calibration: self.ransac.calibration_frame_counter = 0 diff --git a/EyeTrackApp/daddy.py b/EyeTrackApp/daddy.py index c461d14..59e458f 100644 --- a/EyeTrackApp/daddy.py +++ b/EyeTrackApp/daddy.py @@ -34,7 +34,7 @@ import cv2 import onnxruntime from one_euro_filter import OneEuroFilter -from utils.misc_utils import FastMedian +from utils.misc_utils import FastMedian, resource_path # DADDY # Please change the name of this script and the name of the method if you have something better. @@ -211,7 +211,7 @@ class DADDY_cls(object): options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL - ort_session = onnxruntime.InferenceSession(model_file, sess_options=options, providers=["CPUExecutionProvider"]) + ort_session = onnxruntime.InferenceSession(resource_path(model_file), sess_options=options, providers=["CPUExecutionProvider"]) ort_session.set_providers(['CPUExecutionProvider']) # only cpu mode self.ort_session = ort_session diff --git a/EyeTrackApp/eye_processor.py b/EyeTrackApp/eye_processor.py index 9a51bb9..129d459 100644 --- a/EyeTrackApp/eye_processor.py +++ b/EyeTrackApp/eye_processor.py @@ -47,7 +47,7 @@ import numpy as np import cv2 from enum import Enum from one_euro_filter import OneEuroFilter -from utils.misc_utils import PlaySound, SND_FILENAME, SND_ASYNC +from utils.misc_utils import PlaySound, SND_FILENAME, SND_ASYNC, resource_path import importlib from osc import EyeId from osc_calibrate_filter import * @@ -75,7 +75,7 @@ def run_once(f): async def delayed_setting_change(setting, value): await asyncio.sleep(5) setting = value - PlaySound("Audio/completed.wav", SND_FILENAME | SND_ASYNC) + PlaySound(resource_path("Audio/completed.wav"), SND_FILENAME | SND_ASYNC) class EyeProcessor: diff --git a/EyeTrackApp/eyetrackapp.py b/EyeTrackApp/eyetrackapp.py index be44fb7..6b5ee3a 100644 --- a/EyeTrackApp/eyetrackapp.py +++ b/EyeTrackApp/eyetrackapp.py @@ -12,7 +12,7 @@ from osc import VRChatOSCReceiver, VRChatOSC from general_settings_widget import SettingsWidget from algo_settings_widget import AlgoSettingsWidget -from utils.misc_utils import is_nt +from utils.misc_utils import is_nt, resource_path if is_nt: from winotify import Notification @@ -38,6 +38,7 @@ page_url = "https://github.com/RedHawk989/EyeTrackVR/releases/latest" appversion = "EyeTrackApp 0.2.0 BETA 7" + def main(): # Get Configuration config: EyeTrackConfig = EyeTrackConfig.load() @@ -64,7 +65,8 @@ def main(): try: if is_nt: cwd = os.getcwd() - icon = cwd + "\Images\logo.ico" + #icon = cwd + "\Images\logo.ico" + icon = resource_path("Images/logo.ico") toast = Notification( app_id="EyeTrackApp", title="New Update Available!", @@ -187,7 +189,7 @@ def main(): # Create the window window = sg.Window( - f"{appversion}", layout, icon="Images/logo.ico", background_color="#292929" + f"{appversion}", layout, icon=resource_path("Images/logo.ico"), background_color="#292929" ) # GUI Render loop diff --git a/EyeTrackApp/eyetrackapp.spec b/EyeTrackApp/eyetrackapp.spec index fb61b01..101e35d 100644 --- a/EyeTrackApp/eyetrackapp.spec +++ b/EyeTrackApp/eyetrackapp.spec @@ -1,42 +1,47 @@ -# -*- mode: py -3.10 ; coding: utf-8 -*- +# -*- mode: python ; coding: utf-8 -*- + import sys ; sys.setrecursionlimit(sys.getrecursionlimit() * 5) + block_cipher = None +resources=[("Audio/*", "Audio"), ("Images/*", "Images/"), ("pye3d/refraction_models/*", "pye3d/refraction_models/"), ("Models/*", "Models/")] -a = Analysis(['eyetrackapp.py'], - pathex=[], - binaries=[], - datas=[("Audio/*", "Audio"), ("Images/*", "Images/"), ("pye3d/refraction_models/*", "pye3d/refraction_models/"), ("Models/*", "Models/")], - hiddenimports=['cv2', 'numpy', 'PySimpleGui'], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False) -pyz = PYZ(a.pure, a.zipped_data, - cipher=block_cipher) +a = Analysis( +['eyetrackapp.py'], +pathex=[], +binaries=[], +datas=resources, +hiddenimports=['cv2', 'numpy', 'PySimpleGui'], +hookspath=[], +hooksconfig={}, +runtime_hooks=[], +excludes=[], +win_no_prefer_redirects=False, +win_private_assemblies=False, +cipher=block_cipher, +noarchive=False +) -exe = EXE(pyz, - a.scripts, - a.binaries, - a.zipfiles, - a.datas, - [], - exclude_binaries=True, - name='eyetrackapp', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=True, - runtime_tmpdir=None, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, - icon="Images/logo.ico" ) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='eyetrackapp', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon="Images/logo.ico", +) diff --git a/EyeTrackApp/leap.py b/EyeTrackApp/leap.py index 7507742..8cc01ab 100644 --- a/EyeTrackApp/leap.py +++ b/EyeTrackApp/leap.py @@ -37,7 +37,7 @@ from queue import Queue import threading from one_euro_filter import OneEuroFilter import psutil, os -import sys +import sysfrom utils.misc_utils import resource_path frames = 0 @@ -76,7 +76,7 @@ class LEAP_C(object): # Config variables self.num_threads = 3 # Number of python threads to use (using ~1 more than needed to acheive wanted fps yeilds lower cpu usage) self.queue_max_size = 1 # Optimize for best CPU usage, Memory, and Latency. A maxsize is needed to not create a potential memory leak. - self.model_path = 'Models/mommy072623.onnx' + self.model_path = resource_path('Models/mommy072623.onnx') self.interval = 1 # FPS print update rate self.low_priority = True # set process priority to low self.print_fps = True diff --git a/EyeTrackApp/osc_calibrate_filter.py b/EyeTrackApp/osc_calibrate_filter.py index 8b27e62..86cd6ca 100644 --- a/EyeTrackApp/osc_calibrate_filter.py +++ b/EyeTrackApp/osc_calibrate_filter.py @@ -1,7 +1,7 @@ import numpy as np from enum import IntEnum -from utils.misc_utils import PlaySound, SND_FILENAME, SND_ASYNC +from utils.misc_utils import PlaySound, SND_FILENAME, SND_ASYNC, resource_path class EyeId(IntEnum): RIGHT = 0 @@ -27,7 +27,7 @@ class cal(): self.config.calib_XOFF = cx self.config.calib_YOFF = cy self.baseconfig.save() - PlaySound('Audio/completed.wav', SND_FILENAME | SND_ASYNC) + PlaySound(resource_path('Audio/completed.wav'), SND_FILENAME | SND_ASYNC) if self.calibration_frame_counter == self.settings.calibration_samples: self.config.calib_XMAX = -69420 self.config.calib_XMIN = 69420 @@ -54,7 +54,7 @@ class cal(): self.config.calib_YOFF = cy if self.ts == 0: self.settings.gui_recenter_eyes = False - PlaySound('Audio/completed.wav', SND_FILENAME | SND_ASYNC) + PlaySound(resource_path('Audio/completed.wav'), SND_FILENAME | SND_ASYNC) else: self.ts = self.ts - 1 else: diff --git a/EyeTrackApp/utils/misc_utils.py b/EyeTrackApp/utils/misc_utils.py index c205fe7..dbf70ec 100644 --- a/EyeTrackApp/utils/misc_utils.py +++ b/EyeTrackApp/utils/misc_utils.py @@ -1,5 +1,6 @@ import os import typing +import sys is_nt = True if os.name == "nt" else False @@ -57,4 +58,14 @@ class FastMedian: def __medianPrim(self, all): if self.__median is None: self.__median = lst_median(all, ordered=False) - return self.__median \ No newline at end of file + return self.__median + +def resource_path(relative_path): + """ Get absolute path to resource, works for dev and for PyInstaller """ + try: + # PyInstaller creates a temp folder and stores path in _MEIPASS + base_path = sys._MEIPASS + except AttributeError: + base_path = os.path.abspath(".") + + return os.path.join(base_path, relative_path) \ No newline at end of file diff --git a/Makefile b/Makefile index 25bfb0f..2079c76 100644 --- a/Makefile +++ b/Makefile @@ -4,17 +4,16 @@ install: poetry install run: - cd EyeTrackApp/ && poetry run python3 eyetrackapp.py + cd EyeTrackApp/ && poetry run python eyetrackapp.py pyinstaller: - poetry run pyinstaller eyetrackapp.spec EyeTrackApp/eyetrackapp.py + poetry run pyinstaller EyeTrackApp/eyetrackapp.spec EyeTrackApp/eyetrackapp.py clean: - rm eyetrack_settings.json - rm EyeTrackApp/eyetrack_settings.json - rm EyeTrackApp/eyetrack_settings.backup + rm -rf build/ + rm -rf dist/ rm -rf EyeTrackApp/__pycache__/ rm -rf EyeTrackApp/app/__pycache__/ rm -rf EyeTrackApp/app/algorithms/__pycache__/ - rm -rf build/ - rm -rf dist/ \ No newline at end of file + rm EyeTrackApp/eyetrack_settings.backup + rm EyeTrackApp/eyetrack_settings.json \ No newline at end of file