eye-annotation-tool 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. eye_annotation_tool-1.0.0/.github/workflows/publish.yml +33 -0
  2. eye_annotation_tool-1.0.0/.gitignore +170 -0
  3. eye_annotation_tool-1.0.0/LICENSE +21 -0
  4. eye_annotation_tool-1.0.0/PKG-INFO +117 -0
  5. eye_annotation_tool-1.0.0/README.md +90 -0
  6. eye_annotation_tool-1.0.0/ai/README.md +54 -0
  7. eye_annotation_tool-1.0.0/ai/__init__.py +6 -0
  8. eye_annotation_tool-1.0.0/ai/plugin_interface.py +28 -0
  9. eye_annotation_tool-1.0.0/ai/plugin_manager.py +119 -0
  10. eye_annotation_tool-1.0.0/ai/plugins/__init__.py +4 -0
  11. eye_annotation_tool-1.0.0/ai/plugins/eyelid_detectors/__init__.py +1 -0
  12. eye_annotation_tool-1.0.0/ai/plugins/eyelid_detectors/placeholder_eyelid_detector.py +42 -0
  13. eye_annotation_tool-1.0.0/ai/plugins/glint_detectors/__init__.py +0 -0
  14. eye_annotation_tool-1.0.0/ai/plugins/glint_detectors/threshold_glint_detector.py +80 -0
  15. eye_annotation_tool-1.0.0/ai/plugins/iris_detectors/__init__.py +1 -0
  16. eye_annotation_tool-1.0.0/ai/plugins/iris_detectors/placeholder_iris_detector.py +45 -0
  17. eye_annotation_tool-1.0.0/ai/plugins/pupil_detectors/__init__.py +1 -0
  18. eye_annotation_tool-1.0.0/ai/plugins/pupil_detectors/pupil_core_detector.py +50 -0
  19. eye_annotation_tool-1.0.0/ai/plugins/pupil_detectors/threshold_pupil_detector.py +92 -0
  20. eye_annotation_tool-1.0.0/annotation_app/__init__.py +9 -0
  21. eye_annotation_tool-1.0.0/annotation_app/_version.py +34 -0
  22. eye_annotation_tool-1.0.0/annotation_app/controllers/__init__.py +6 -0
  23. eye_annotation_tool-1.0.0/annotation_app/controllers/annotation_controller.py +88 -0
  24. eye_annotation_tool-1.0.0/annotation_app/controllers/navigation_controller.py +84 -0
  25. eye_annotation_tool-1.0.0/annotation_app/gui/__init__.py +19 -0
  26. eye_annotation_tool-1.0.0/annotation_app/gui/ai_assist_handler.py +157 -0
  27. eye_annotation_tool-1.0.0/annotation_app/gui/annotation_controls.py +136 -0
  28. eye_annotation_tool-1.0.0/annotation_app/gui/custom_widgets.py +279 -0
  29. eye_annotation_tool-1.0.0/annotation_app/gui/image_viewer.py +847 -0
  30. eye_annotation_tool-1.0.0/annotation_app/gui/main_window.py +323 -0
  31. eye_annotation_tool-1.0.0/annotation_app/gui/menu_handler.py +110 -0
  32. eye_annotation_tool-1.0.0/annotation_app/gui/shortcut_handler.py +53 -0
  33. eye_annotation_tool-1.0.0/annotation_app/main.py +26 -0
  34. eye_annotation_tool-1.0.0/annotation_app/resources/Funded_by_EU_Eyes4ICU.png +0 -0
  35. eye_annotation_tool-1.0.0/annotation_app/resources/app_icon.ico +0 -0
  36. eye_annotation_tool-1.0.0/annotation_app/resources/main_page.png +0 -0
  37. eye_annotation_tool-1.0.0/annotation_app/utils/__init__.py +14 -0
  38. eye_annotation_tool-1.0.0/annotation_app/utils/annotation_io.py +153 -0
  39. eye_annotation_tool-1.0.0/annotation_app/utils/image_processing.py +70 -0
  40. eye_annotation_tool-1.0.0/annotation_app/utils/settings_handler.py +59 -0
  41. eye_annotation_tool-1.0.0/pyproject.toml +160 -0
  42. eye_annotation_tool-1.0.0/run.py +6 -0
  43. eye_annotation_tool-1.0.0/uv.lock +790 -0
@@ -0,0 +1,33 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ deploy:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with:
14
+ fetch-depth: 0
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v5
18
+ with:
19
+ python-version: '3.11'
20
+
21
+ - name: Install dependencies
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install build twine
25
+
26
+ - name: Build package
27
+ run: python -m build
28
+
29
+ - name: Publish to PyPI
30
+ env:
31
+ TWINE_USERNAME: __token__
32
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
33
+ run: twine upload dist/*
@@ -0,0 +1,170 @@
1
+ .vscode
2
+ ai/settings.json
3
+ .DS_Store
4
+ annotation_app/_version.py
5
+
6
+ # Byte-compiled / optimized / DLL files
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+
11
+ # C extensions
12
+ *.so
13
+
14
+ # Distribution / packaging
15
+ .Python
16
+ build/
17
+ develop-eggs/
18
+ dist/
19
+ downloads/
20
+ eggs/
21
+ .eggs/
22
+ lib/
23
+ lib64/
24
+ parts/
25
+ sdist/
26
+ var/
27
+ wheels/
28
+ share/python-wheels/
29
+ *.egg-info/
30
+ .installed.cfg
31
+ *.egg
32
+ MANIFEST
33
+
34
+ # PyInstaller
35
+ # Usually these files are written by a python script from a template
36
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
37
+ *.manifest
38
+ *.spec
39
+
40
+ # Installer logs
41
+ pip-log.txt
42
+ pip-delete-this-directory.txt
43
+
44
+ # Unit test / coverage reports
45
+ htmlcov/
46
+ .tox/
47
+ .nox/
48
+ .coverage
49
+ .coverage.*
50
+ .cache
51
+ nosetests.xml
52
+ coverage.xml
53
+ *.cover
54
+ *.py,cover
55
+ .hypothesis/
56
+ .pytest_cache/
57
+ cover/
58
+
59
+ # Translations
60
+ *.mo
61
+ *.pot
62
+
63
+ # Django stuff:
64
+ *.log
65
+ local_settings.py
66
+ db.sqlite3
67
+ db.sqlite3-journal
68
+
69
+ # Flask stuff:
70
+ instance/
71
+ .webassets-cache
72
+
73
+ # Scrapy stuff:
74
+ .scrapy
75
+
76
+ # Sphinx documentation
77
+ docs/_build/
78
+
79
+ # PyBuilder
80
+ .pybuilder/
81
+ target/
82
+
83
+ # Jupyter Notebook
84
+ .ipynb_checkpoints
85
+
86
+ # IPython
87
+ profile_default/
88
+ ipython_config.py
89
+
90
+ # pyenv
91
+ # For a library or package, you might want to ignore these files since the code is
92
+ # intended to run in multiple environments; otherwise, check them in:
93
+ # .python-version
94
+
95
+ # uv
96
+ .python-version
97
+
98
+ # pipenv
99
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
100
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
101
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
102
+ # install all needed dependencies.
103
+ #Pipfile.lock
104
+
105
+ # poetry
106
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
107
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
108
+ # commonly ignored for libraries.
109
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
110
+ #poetry.lock
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ #pdm.lock
115
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
116
+ # in version control.
117
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
118
+ .pdm.toml
119
+ .pdm-python
120
+ .pdm-build/
121
+
122
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
123
+ __pypackages__/
124
+
125
+ # Celery stuff
126
+ celerybeat-schedule
127
+ celerybeat.pid
128
+
129
+ # SageMath parsed files
130
+ *.sage.py
131
+
132
+ # Environments
133
+ .env
134
+ .venv
135
+ env/
136
+ venv/
137
+ ENV/
138
+ env.bak/
139
+ venv.bak/
140
+
141
+ # Spyder project settings
142
+ .spyderproject
143
+ .spyproject
144
+
145
+ # Rope project settings
146
+ .ropeproject
147
+
148
+ # mkdocs documentation
149
+ /site
150
+
151
+ # mypy
152
+ .mypy_cache/
153
+ .dmypy.json
154
+ dmypy.json
155
+
156
+ # Pyre type checker
157
+ .pyre/
158
+
159
+ # pytype static type analyzer
160
+ .pytype/
161
+
162
+ # Cython debug symbols
163
+ cython_debug/
164
+
165
+ # PyCharm
166
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
167
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
168
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
169
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
170
+ #.idea/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Mohammadhossein Salari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: eye_annotation_tool
3
+ Version: 1.0.0
4
+ Summary: A tool for annotating pupil and iris in eye images
5
+ Project-URL: Homepage, https://github.com/mh-salari/eye_annotation_tool
6
+ Project-URL: Repository, https://github.com/mh-salari/eye_annotation_tool
7
+ Project-URL: Issues, https://github.com/mh-salari/eye_annotation_tool/issues
8
+ Author-email: Mohammadhossein Salari <mohammadhossein.salari@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: annotation,computer vision,eye,eyelid,iris,pupil
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Requires-Python: >=3.8
21
+ Requires-Dist: numpy>=1.20.0
22
+ Requires-Dist: opencv-python>=4.5.0
23
+ Requires-Dist: pupil-detectors>=2.0.0
24
+ Requires-Dist: pyqt5>=5.15.0
25
+ Requires-Dist: scipy>=1.7.0
26
+ Description-Content-Type: text/markdown
27
+
28
+ # EyE Annotation Tool
29
+
30
+ EyE Annotation Tool is a tool for annotating pupil, iris and eyelid in eye images. It provides a user-friendly interface for manual annotation and supports AI-assisted detection.
31
+
32
+ <p align="center">
33
+ <img src="annotation_app/resources/main_page.png" alt="EyE Annotation Tool Main Page" width="800">
34
+ </p>
35
+
36
+ ## Features
37
+
38
+ - Load and navigate through multiple eye images
39
+ - Manual annotation of pupil, iris, eyelid, and glints
40
+ - AI-assisted detection of pupil, iris, eyelid, and glints
41
+ - Undo functionality for annotations
42
+ - Save and load annotations
43
+ - Extensible plugin system for custom detectors
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install eye_annotation_tool
49
+ ```
50
+
51
+ For the latest development version:
52
+
53
+ ```bash
54
+ pip install git+https://github.com/mh-salari/eye_annotation_tool.git
55
+ ```
56
+
57
+ ### Using uv
58
+
59
+ If you prefer [uv](https://docs.astral.sh/uv/):
60
+
61
+ ```bash
62
+ git clone https://github.com/mh-salari/eye_annotation_tool.git
63
+ cd eye_annotation_tool
64
+ uv sync
65
+ ```
66
+
67
+ > **Apple Silicon (M1/M2/M3) Note:** The `pupil-detectors` dependency only provides pre-built wheels for x86_64. On Apple Silicon Macs, you need to use an x86_64 Python via Rosetta 2:
68
+ >
69
+ > ```bash
70
+ > uv python install cpython-3.11-macos-x86_64
71
+ > uv python pin cpython-3.11-macos-x86_64
72
+ > uv sync
73
+ > ```
74
+
75
+ ## Usage
76
+
77
+ ```bash
78
+ eye_annotation_tool
79
+ ```
80
+
81
+ Or with uv:
82
+
83
+ ```bash
84
+ uv run eye_annotation_tool
85
+ ```
86
+
87
+ Or run it as a module:
88
+
89
+ ```bash
90
+ python -m eye_annotation_tool
91
+ ```
92
+
93
+ ## Adding Custom Plugins
94
+
95
+ EyE Annotation Tool supports custom plugins for pupil, iris and eyelid detection. To add a new plugin:
96
+
97
+ 1. Create a new Python file in the appropriate plugin directory.
98
+ 2. Define your detector class in this file.
99
+ 3. Ensure your detector follows the required interface.
100
+
101
+ For a detailed guide on creating plugins, see the [Plugin Development Guide](ai/README.md) in the `ai` directory.
102
+
103
+ ## Contributing
104
+
105
+ Contributions are welcome! Please feel free to submit a Pull Request.
106
+
107
+ ## License
108
+
109
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
110
+
111
+ ## Acknowledgments
112
+
113
+ This project has received funding from the European Union's Horizon Europe research and innovation funding program under grant agreement No 101072410, Eyes4ICU project.
114
+
115
+ <p align="center">
116
+ <img src="annotation_app/resources/Funded_by_EU_Eyes4ICU.png" alt="Funded by EU Eyes4ICU" width="500">
117
+ </p>
@@ -0,0 +1,90 @@
1
+ # EyE Annotation Tool
2
+
3
+ EyE Annotation Tool is a tool for annotating pupil, iris and eyelid in eye images. It provides a user-friendly interface for manual annotation and supports AI-assisted detection.
4
+
5
+ <p align="center">
6
+ <img src="annotation_app/resources/main_page.png" alt="EyE Annotation Tool Main Page" width="800">
7
+ </p>
8
+
9
+ ## Features
10
+
11
+ - Load and navigate through multiple eye images
12
+ - Manual annotation of pupil, iris, eyelid, and glints
13
+ - AI-assisted detection of pupil, iris, eyelid, and glints
14
+ - Undo functionality for annotations
15
+ - Save and load annotations
16
+ - Extensible plugin system for custom detectors
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install eye_annotation_tool
22
+ ```
23
+
24
+ For the latest development version:
25
+
26
+ ```bash
27
+ pip install git+https://github.com/mh-salari/eye_annotation_tool.git
28
+ ```
29
+
30
+ ### Using uv
31
+
32
+ If you prefer [uv](https://docs.astral.sh/uv/):
33
+
34
+ ```bash
35
+ git clone https://github.com/mh-salari/eye_annotation_tool.git
36
+ cd eye_annotation_tool
37
+ uv sync
38
+ ```
39
+
40
+ > **Apple Silicon (M1/M2/M3) Note:** The `pupil-detectors` dependency only provides pre-built wheels for x86_64. On Apple Silicon Macs, you need to use an x86_64 Python via Rosetta 2:
41
+ >
42
+ > ```bash
43
+ > uv python install cpython-3.11-macos-x86_64
44
+ > uv python pin cpython-3.11-macos-x86_64
45
+ > uv sync
46
+ > ```
47
+
48
+ ## Usage
49
+
50
+ ```bash
51
+ eye_annotation_tool
52
+ ```
53
+
54
+ Or with uv:
55
+
56
+ ```bash
57
+ uv run eye_annotation_tool
58
+ ```
59
+
60
+ Or run it as a module:
61
+
62
+ ```bash
63
+ python -m eye_annotation_tool
64
+ ```
65
+
66
+ ## Adding Custom Plugins
67
+
68
+ EyE Annotation Tool supports custom plugins for pupil, iris and eyelid detection. To add a new plugin:
69
+
70
+ 1. Create a new Python file in the appropriate plugin directory.
71
+ 2. Define your detector class in this file.
72
+ 3. Ensure your detector follows the required interface.
73
+
74
+ For a detailed guide on creating plugins, see the [Plugin Development Guide](ai/README.md) in the `ai` directory.
75
+
76
+ ## Contributing
77
+
78
+ Contributions are welcome! Please feel free to submit a Pull Request.
79
+
80
+ ## License
81
+
82
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
83
+
84
+ ## Acknowledgments
85
+
86
+ This project has received funding from the European Union's Horizon Europe research and innovation funding program under grant agreement No 101072410, Eyes4ICU project.
87
+
88
+ <p align="center">
89
+ <img src="annotation_app/resources/Funded_by_EU_Eyes4ICU.png" alt="Funded by EU Eyes4ICU" width="500">
90
+ </p>
@@ -0,0 +1,54 @@
1
+ # Creating a New Plugin for EyE Annotation Tool
2
+
3
+ This guide explains how to create a new pupil, iris or eyelid detector plugin for the EyE Annotation Tool application.
4
+
5
+ ## Steps to Create a New Plugin
6
+
7
+ 1. Create a new Python file in the appropriate directory:
8
+ - For pupil detectors: `ai/plugins/pupil_detectors/`
9
+ - For iris detectors: `ai/plugins/iris_detectors/`
10
+ - For eyelid detectors: `ai/plugins/eyelid_detectors/`
11
+
12
+ 2. Import the necessary modules:
13
+ ```python
14
+ from ai.plugin_interface import DetectorPlugin
15
+ import numpy as np
16
+ ```
17
+
18
+ 3. Create a new class that inherits from `DetectorPlugin`:
19
+ ```python
20
+ class MyNewDetector(DetectorPlugin):
21
+ def __init__(self):
22
+ # Initialize your detector here
23
+ pass
24
+
25
+ def detect(self, image_path):
26
+ # Implement your detection algorithm here
27
+ # Return the ellipse parameters and points
28
+ return ellipse, points
29
+
30
+ @property
31
+ def name(self):
32
+ # Return a unique name for your detector
33
+ return "my_new_detector"
34
+ ```
35
+
36
+ 4. Implement the `detect` method:
37
+ - Input: `image_path` path of the eye image
38
+ - Output: `ellipse` (dict with keys: 'center', 'axes', 'angle') and `points` (list of point coordinates)
39
+
40
+ 5. Set a unique `name` for your detector in the `name` property.
41
+
42
+ 6. Save your file with a descriptive name (e.g., `my_new_detector.py`).
43
+
44
+ The plugin manager will automatically discover and load your new plugin when the application starts.
45
+
46
+ ## Example
47
+
48
+ See `placeholder_iris_detector.py` for a simple example of a detector plugin.
49
+
50
+ ## Notes
51
+
52
+ - Ensure your detector class inherits from `DetectorPlugin` and implements all required methods.
53
+ - The `name` property should return a unique string to identify your detector.
54
+ - Your `detect` method should handle various image sizes and conditions robustly.
@@ -0,0 +1,6 @@
1
+ """AI plugin system for eye annotation detectors."""
2
+
3
+ from .plugin_interface import DetectorPlugin
4
+ from .plugin_manager import PluginManager
5
+
6
+ __all__ = ["DetectorPlugin", "PluginManager"]
@@ -0,0 +1,28 @@
1
+ """Abstract base class for detector plugins."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+
6
+ class DetectorPlugin(ABC):
7
+ """Base class for all detector plugins (pupil, iris, eyelid)."""
8
+
9
+ @abstractmethod
10
+ def __init__(self) -> None:
11
+ """Initialize the detector plugin."""
12
+
13
+ @abstractmethod
14
+ def detect(self, image: str) -> tuple | list:
15
+ """Detect features in the given image.
16
+
17
+ Args:
18
+ image: Path to the image file.
19
+
20
+ Returns:
21
+ Detection results as tuple or list depending on detector type.
22
+
23
+ """
24
+
25
+ @property
26
+ @abstractmethod
27
+ def name(self) -> str:
28
+ """Get the name of the detector plugin."""
@@ -0,0 +1,119 @@
1
+ """Plugin manager for loading and managing detector plugins."""
2
+
3
+ import importlib.util
4
+ from pathlib import Path
5
+
6
+ from .plugin_interface import DetectorPlugin
7
+
8
+
9
+ class PluginManager:
10
+ """Manages loading and accessing detector plugins for pupil, iris, and eyelid detection."""
11
+
12
+ def __init__(self) -> None:
13
+ """Initialize the PluginManager."""
14
+ self.pupil_detectors = {}
15
+ self.iris_detectors = {}
16
+ self.eyelid_detectors = {}
17
+ self.load_plugins()
18
+
19
+ def load_plugins(self) -> None:
20
+ """Load all detector plugins from the plugins directory."""
21
+ plugin_dirs = [
22
+ Path(__file__).parent / "plugins" / "pupil_detectors",
23
+ Path(__file__).parent / "plugins" / "iris_detectors",
24
+ Path(__file__).parent / "plugins" / "eyelid_detectors",
25
+ ]
26
+
27
+ for plugin_dir in plugin_dirs:
28
+ self.load_plugins_from_directory(plugin_dir)
29
+
30
+ def load_plugins_from_directory(self, directory: Path) -> None:
31
+ """Load plugins from a specific directory and register them by type.
32
+
33
+ Args:
34
+ directory: Path to the directory containing plugin files.
35
+
36
+ """
37
+ plugin_type = Path(directory).name
38
+ for file_path in Path(directory).iterdir():
39
+ if file_path.suffix == ".py" and not file_path.name.startswith("__"):
40
+ module_name = file_path.stem
41
+ module_path = str(file_path)
42
+ spec = importlib.util.spec_from_file_location(module_name, module_path)
43
+ module = importlib.util.module_from_spec(spec)
44
+ spec.loader.exec_module(module)
45
+ for item_name in dir(module):
46
+ item = getattr(module, item_name)
47
+ if isinstance(item, type) and issubclass(item, DetectorPlugin) and item is not DetectorPlugin:
48
+ plugin_instance = item()
49
+ if plugin_type == "pupil_detectors":
50
+ self.pupil_detectors[plugin_instance.name] = plugin_instance
51
+ elif plugin_type == "iris_detectors":
52
+ self.iris_detectors[plugin_instance.name] = plugin_instance
53
+ elif plugin_type == "eyelid_detectors":
54
+ self.eyelid_detectors[plugin_instance.name] = plugin_instance
55
+ else:
56
+ print(f"Unknown plugin type: {plugin_type}")
57
+
58
+ def get_pupil_detector(self, name: str) -> DetectorPlugin | None:
59
+ """Get a pupil detector plugin by name.
60
+
61
+ Args:
62
+ name: Name of the pupil detector.
63
+
64
+ Returns:
65
+ The detector plugin instance or None if not found.
66
+
67
+ """
68
+ return self.pupil_detectors.get(name)
69
+
70
+ def get_iris_detector(self, name: str) -> DetectorPlugin | None:
71
+ """Get an iris detector plugin by name.
72
+
73
+ Args:
74
+ name: Name of the iris detector.
75
+
76
+ Returns:
77
+ The detector plugin instance or None if not found.
78
+
79
+ """
80
+ return self.iris_detectors.get(name)
81
+
82
+ def get_pupil_detector_names(self) -> list[str]:
83
+ """Get list of available pupil detector names.
84
+
85
+ Returns:
86
+ List of pupil detector names.
87
+
88
+ """
89
+ return list(self.pupil_detectors.keys())
90
+
91
+ def get_iris_detector_names(self) -> list[str]:
92
+ """Get list of available iris detector names.
93
+
94
+ Returns:
95
+ List of iris detector names.
96
+
97
+ """
98
+ return list(self.iris_detectors.keys())
99
+
100
+ def get_eyelid_detector(self, name: str) -> DetectorPlugin | None:
101
+ """Get an eyelid detector plugin by name.
102
+
103
+ Args:
104
+ name: Name of the eyelid detector.
105
+
106
+ Returns:
107
+ The detector plugin instance or None if not found.
108
+
109
+ """
110
+ return self.eyelid_detectors.get(name)
111
+
112
+ def get_eyelid_detector_names(self) -> list[str]:
113
+ """Get list of available eyelid detector names.
114
+
115
+ Returns:
116
+ List of eyelid detector names.
117
+
118
+ """
119
+ return list(self.eyelid_detectors.keys())
@@ -0,0 +1,4 @@
1
+ """AI detector plugins for pupil, iris, and eyelid detection."""
2
+
3
+ # This file can be left empty
4
+ # It marks the plugins directory as a Python package
@@ -0,0 +1 @@
1
+ """Eyelid detector plugins."""
@@ -0,0 +1,42 @@
1
+ """Placeholder eyelid detector for testing purposes."""
2
+
3
+ from ai.plugin_interface import DetectorPlugin
4
+
5
+
6
+ class PlaceholderEyelidDetector(DetectorPlugin):
7
+ """Placeholder eyelid detector that returns dummy contour points."""
8
+
9
+ def __init__(self) -> None:
10
+ """Initialize the PlaceholderEyelidDetector."""
11
+
12
+ def detect(self, image_path: str) -> list[tuple[float, float]]: # noqa: PLR6301 ARG002
13
+ """Detect eyelid contour in the given image (returns placeholder data).
14
+
15
+ Args:
16
+ image_path: Path to the image file.
17
+
18
+ Returns:
19
+ List of points representing the eyelid contour.
20
+
21
+ """
22
+ # For this example, we'll ignore the actual image content
23
+ # and just return 4 fixed points representing an eyelid contour
24
+
25
+ # Assuming image size of 192x192 (same as in the iris example)
26
+ height, width = 192, 192
27
+
28
+ # Define 4 points for the eyelid contour
29
+ # These points form a simple curve across the top of the "eye"
30
+ points = [
31
+ (width * 0.2, height * 0.3), # Left point
32
+ (width * 0.4, height * 0.2), # Left-middle point
33
+ (width * 0.6, height * 0.2), # Right-middle point
34
+ (width * 0.8, height * 0.3), # Right point
35
+ ]
36
+
37
+ return points
38
+
39
+ @property
40
+ def name(self) -> str:
41
+ """Get the name of the detector plugin."""
42
+ return "test"