mouse-pupil-analysis 0.2.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 (111) hide show
  1. mouse_pupil_analysis-0.2.0/LICENSE +21 -0
  2. mouse_pupil_analysis-0.2.0/MANIFEST.in +6 -0
  3. mouse_pupil_analysis-0.2.0/PKG-INFO +360 -0
  4. mouse_pupil_analysis-0.2.0/README.md +321 -0
  5. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/__init__.py +82 -0
  6. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/api.py +232 -0
  7. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/augmentation.py +323 -0
  8. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/checkpoints/training_log_unet_atn_resize_166pupils_thresh=0.7_iou=0.9158.txt +200 -0
  9. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/checkpoints/unet_atn_resize_166pupils_thresh=0.7_iou=0.9158.pth +0 -0
  10. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/dataset.py +78 -0
  11. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/extract_frames.py +196 -0
  12. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/logging_utils.py +23 -0
  13. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/plotting.py +85 -0
  14. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/preprocessing.py +108 -0
  15. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/pupil_predictions.py +481 -0
  16. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/results.py +138 -0
  17. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/run_pupil_analysis.py +117 -0
  18. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/tracking.py +362 -0
  19. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis/unet.py +76 -0
  20. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis.egg-info/PKG-INFO +360 -0
  21. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis.egg-info/SOURCES.txt +109 -0
  22. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis.egg-info/dependency_links.txt +1 -0
  23. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis.egg-info/entry_points.txt +3 -0
  24. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis.egg-info/requires.txt +15 -0
  25. mouse_pupil_analysis-0.2.0/mouse_pupil_analysis.egg-info/top_level.txt +1 -0
  26. mouse_pupil_analysis-0.2.0/pyproject.toml +100 -0
  27. mouse_pupil_analysis-0.2.0/sample_data/README.md +86 -0
  28. mouse_pupil_analysis-0.2.0/sample_data/images_train/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_0000.png +0 -0
  29. mouse_pupil_analysis-0.2.0/sample_data/images_train/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_9215.png +0 -0
  30. mouse_pupil_analysis-0.2.0/sample_data/images_train/250616_5120_Purple_sleep_trial_1_2025-06-16T16-31-19.701_17700.png +0 -0
  31. mouse_pupil_analysis-0.2.0/sample_data/images_train/250616_5120_Purple_sleep_trial_1_2025-06-16T16-31-19.701_19260.png +0 -0
  32. mouse_pupil_analysis-0.2.0/sample_data/images_train/251018_5213_Purple_awake pupil recording_2025-10-18T13-47-06.854_00127.png +0 -0
  33. mouse_pupil_analysis-0.2.0/sample_data/images_train/HQL073_250515_002_eye_36845.png +0 -0
  34. mouse_pupil_analysis-0.2.0/sample_data/images_train/HQL080_sleep250625_003_eye_39360.png +0 -0
  35. mouse_pupil_analysis-0.2.0/sample_data/images_train/HQL086_sleep250909_011_eye_29786.png +0 -0
  36. mouse_pupil_analysis-0.2.0/sample_data/images_validation/HQL080_sleep250625_003_eye_48292.png +0 -0
  37. mouse_pupil_analysis-0.2.0/sample_data/images_validation/HQL086_sleep250909_011_eye_22730.png +0 -0
  38. mouse_pupil_analysis-0.2.0/sample_data/images_validation/HQL090_sleep251012_010_eye_06588.png +0 -0
  39. mouse_pupil_analysis-0.2.0/sample_data/images_validation/HQL090_whiskerb251020_009_eye_15701.png +0 -0
  40. mouse_pupil_analysis-0.2.0/sample_data/manifest.csv +50 -0
  41. mouse_pupil_analysis-0.2.0/sample_data/masks_train/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_0000.png +0 -0
  42. mouse_pupil_analysis-0.2.0/sample_data/masks_train/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_9215.png +0 -0
  43. mouse_pupil_analysis-0.2.0/sample_data/masks_train/250616_5120_Purple_sleep_trial_1_2025-06-16T16-31-19.701_17700.png +0 -0
  44. mouse_pupil_analysis-0.2.0/sample_data/masks_train/250616_5120_Purple_sleep_trial_1_2025-06-16T16-31-19.701_19260.png +0 -0
  45. mouse_pupil_analysis-0.2.0/sample_data/masks_train/251018_5213_Purple_awake pupil recording_2025-10-18T13-47-06.854_00127.png +0 -0
  46. mouse_pupil_analysis-0.2.0/sample_data/masks_train/HQL073_250515_002_eye_36845.png +0 -0
  47. mouse_pupil_analysis-0.2.0/sample_data/masks_train/HQL080_sleep250625_003_eye_39360.png +0 -0
  48. mouse_pupil_analysis-0.2.0/sample_data/masks_train/HQL086_sleep250909_011_eye_29786.png +0 -0
  49. mouse_pupil_analysis-0.2.0/sample_data/masks_validation/HQL080_sleep250625_003_eye_48292.png +0 -0
  50. mouse_pupil_analysis-0.2.0/sample_data/masks_validation/HQL086_sleep250909_011_eye_22730.png +0 -0
  51. mouse_pupil_analysis-0.2.0/sample_data/masks_validation/HQL090_sleep251012_010_eye_06588.png +0 -0
  52. mouse_pupil_analysis-0.2.0/sample_data/masks_validation/HQL090_whiskerb251020_009_eye_15701.png +0 -0
  53. mouse_pupil_analysis-0.2.0/sample_data/raw_frames/recording_250530/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_00000.png +0 -0
  54. mouse_pupil_analysis-0.2.0/sample_data/raw_frames/recording_250530/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_02500.png +0 -0
  55. mouse_pupil_analysis-0.2.0/sample_data/raw_frames/recording_250530/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_05000.png +0 -0
  56. mouse_pupil_analysis-0.2.0/sample_data/raw_frames/recording_250616/250616_5120_Purple_sleep_trial_1_2025-06-16T16-31-19.701_00000.png +0 -0
  57. mouse_pupil_analysis-0.2.0/sample_data/raw_frames/recording_250616/250616_5120_Purple_sleep_trial_1_2025-06-16T16-31-19.701_02070.png +0 -0
  58. mouse_pupil_analysis-0.2.0/sample_data/raw_frames/recording_250616/250616_5120_Purple_sleep_trial_1_2025-06-16T16-31-19.701_04141.png +0 -0
  59. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07212.png +0 -0
  60. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07213.png +0 -0
  61. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07214.png +0 -0
  62. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07215.png +0 -0
  63. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07216.png +0 -0
  64. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07217.png +0 -0
  65. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07218.png +0 -0
  66. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07219.png +0 -0
  67. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07220.png +0 -0
  68. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07221.png +0 -0
  69. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07222.png +0 -0
  70. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07223.png +0 -0
  71. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07224.png +0 -0
  72. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07225.png +0 -0
  73. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07226.png +0 -0
  74. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07227.png +0 -0
  75. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07228.png +0 -0
  76. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07229.png +0 -0
  77. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07230.png +0 -0
  78. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07231.png +0 -0
  79. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07232.png +0 -0
  80. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07233.png +0 -0
  81. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07234.png +0 -0
  82. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07235.png +0 -0
  83. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07236.png +0 -0
  84. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07237.png +0 -0
  85. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07238.png +0 -0
  86. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07239.png +0 -0
  87. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07240.png +0 -0
  88. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07241.png +0 -0
  89. mouse_pupil_analysis-0.2.0/sample_data/velocity_frames/250530_5003_Green_Training_very_dm_light_2025-05-30T09-27-57.042_07242.png +0 -0
  90. mouse_pupil_analysis-0.2.0/scripts/verify_distribution_namespaces.py +65 -0
  91. mouse_pupil_analysis-0.2.0/setup.cfg +4 -0
  92. mouse_pupil_analysis-0.2.0/tests/test_checkpoints.py +43 -0
  93. mouse_pupil_analysis-0.2.0/tests/test_cli_help.py +20 -0
  94. mouse_pupil_analysis-0.2.0/tests/test_distribution_namespaces.py +41 -0
  95. mouse_pupil_analysis-0.2.0/tests/test_end_to_end.py +118 -0
  96. mouse_pupil_analysis-0.2.0/tests/test_extract_frames.py +46 -0
  97. mouse_pupil_analysis-0.2.0/tests/test_imports.py +25 -0
  98. mouse_pupil_analysis-0.2.0/tests/test_make_gif.py +43 -0
  99. mouse_pupil_analysis-0.2.0/tests/test_metadata.py +88 -0
  100. mouse_pupil_analysis-0.2.0/tests/test_outputs.py +98 -0
  101. mouse_pupil_analysis-0.2.0/tests/test_overlays.py +52 -0
  102. mouse_pupil_analysis-0.2.0/tests/test_plotting_backend.py +71 -0
  103. mouse_pupil_analysis-0.2.0/tests/test_preprocessing.py +48 -0
  104. mouse_pupil_analysis-0.2.0/tests/test_real_images.py +128 -0
  105. mouse_pupil_analysis-0.2.0/tests/test_sample_data.py +75 -0
  106. mouse_pupil_analysis-0.2.0/tests/test_tracking.py +192 -0
  107. mouse_pupil_analysis-0.2.0/tests/test_training_pairing.py +112 -0
  108. mouse_pupil_analysis-0.2.0/training/README.md +117 -0
  109. mouse_pupil_analysis-0.2.0/training/check_augmentation.py +99 -0
  110. mouse_pupil_analysis-0.2.0/training/labelme_json2png.py +34 -0
  111. mouse_pupil_analysis-0.2.0/training/run_train.py +175 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Yue Zhao
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,6 @@
1
+ include mouse_pupil_analysis/checkpoints/*.pth
2
+ include mouse_pupil_analysis/checkpoints/*.txt
3
+ recursive-include sample_data *.csv *.md *.png
4
+ recursive-include scripts *.py
5
+ recursive-include training *.md *.py
6
+ prune mouse_pupil_analysis/checkpoints/archive
@@ -0,0 +1,360 @@
1
+ Metadata-Version: 2.4
2
+ Name: mouse-pupil-analysis
3
+ Version: 0.2.0
4
+ Summary: Automated mouse pupil segmentation, diameter, and pupil-center velocity analysis using UNet.
5
+ Author: Yue Zhao
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/yzhaoinuw/mouse-pupil-analysis
8
+ Project-URL: Repository, https://github.com/yzhaoinuw/mouse-pupil-analysis
9
+ Project-URL: Issues, https://github.com/yzhaoinuw/mouse-pupil-analysis/issues
10
+ Project-URL: Changelog, https://github.com/yzhaoinuw/mouse-pupil-analysis/blob/main/CHANGELOG.md
11
+ Keywords: pupillometry,pupil-tracking,segmentation,unet,neuroscience,mouse
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
20
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: opencv-python>=4.12
25
+ Requires-Dist: numpy>=2.1
26
+ Requires-Dist: tqdm>=4.67
27
+ Requires-Dist: pandas>=2.3
28
+ Requires-Dist: Pillow>=11.0
29
+ Requires-Dist: matplotlib>=3.10
30
+ Requires-Dist: torch>=2.8
31
+ Requires-Dist: torchvision>=0.23
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7; extra == "dev"
34
+ Requires-Dist: black==25.1.0; extra == "dev"
35
+ Requires-Dist: ruff==0.14.14; extra == "dev"
36
+ Requires-Dist: pre-commit>=3; extra == "dev"
37
+ Requires-Dist: build>=1; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ [![Agent Collab Treaty adopted](https://raw.githubusercontent.com/yzhaoinuw/agent_collab_treaty/main/assets/treaty-adopted.svg)](https://github.com/yzhaoinuw/agent_collab_treaty)
41
+
42
+ ![Pupil analysis pipeline demo](media/pupil_diameter_analysis_result_demo.gif)
43
+
44
+ <p align="center"><em>Left: confidence-colored pupil mask and estimated center — Right: evolving pupil diameter, center, and speed</em></p>
45
+
46
+ See [`media/README.md`](media/README.md) to regenerate and review the demo GIF.
47
+
48
+ # Pupil Analysis Pipeline
49
+
50
+ This package runs a full pipeline for **mouse pupil segmentation and size estimation** using a trained UNet model.
51
+ You can start directly from a video file or from an existing folder of extracted frames. To obtain expected results, the video or images provided should have at least the majority of the eye contained in the 148 x 148 pixel area in the center of the frames. This is crucial to getting good results because the model was trained on 148 x 148 centered eye images.
52
+
53
+ ---
54
+
55
+ ## 📦 Installation
56
+
57
+ It is recommended that you first create a dedicated virtual environment, for example with [Miniconda](https://www.anaconda.com/docs/getting-started/miniconda/install):
58
+
59
+ ```bash
60
+ conda create -n mouse_pupil_analysis python=3.12
61
+ conda activate mouse_pupil_analysis
62
+ ```
63
+
64
+ Then install the package:
65
+
66
+ ```bash
67
+ pip install mouse-pupil-analysis
68
+ ```
69
+
70
+ The trained model checkpoint ships with the package, so there is nothing else to download.
71
+
72
+ > **Note on names.** The repository and distribution are `mouse-pupil-analysis`, the Python import is
73
+ > `mouse_pupil_analysis`, and the established console commands remain `run-pupil-analysis` and
74
+ > `extract-frames`. The shorter name `pupil-tracking` on PyPI belongs to an unrelated project by a
75
+ > different author, and it installs its own `pupil_tracking` module, so this project deliberately
76
+ > claims no `pupil_tracking` import namespace of any kind.
77
+ > Existing Conda environments do not need to be renamed; environment names are local only.
78
+
79
+ ### GPU / CPU builds of PyTorch
80
+
81
+ On **Windows and macOS**, the command above installs a CPU-only build of PyTorch, which is all this package needs to run. No action required.
82
+
83
+ On **Linux**, the default PyPI wheel bundles CUDA and is several times larger. If you do not have an NVIDIA GPU, install the CPU-only build first to avoid the download:
84
+
85
+ ```bash
86
+ pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
87
+ pip install mouse-pupil-analysis
88
+ ```
89
+
90
+ To use an **NVIDIA GPU**, install a matching CUDA build first. This package requires
91
+ `torch>=2.8`, which is served by the `cu126`, `cu128`, and `cu129` indexes; older
92
+ indexes such as `cu124` stop at PyTorch 2.6 and will not satisfy that floor. Pick the
93
+ index matching your driver with the [official selector](https://pytorch.org/get-started/locally/):
94
+
95
+ ```bash
96
+ pip install torch torchvision --index-url https://download.pytorch.org/whl/cu126
97
+ pip install mouse-pupil-analysis
98
+ ```
99
+
100
+ Inference selects the GPU automatically when one is available and falls back to CPU otherwise.
101
+
102
+ ### Installing for development
103
+
104
+ ```bash
105
+ git clone https://github.com/yzhaoinuw/mouse-pupil-analysis.git
106
+ cd mouse-pupil-analysis
107
+ pip install -e ".[dev]"
108
+ ```
109
+
110
+
111
+ ## 🏃 Basic Usage
112
+ After installation, you can run pupil analysis on a video like so
113
+ ```bash
114
+ run-pupil-analysis --video_path /path/to/movie.avi
115
+ ```
116
+
117
+ This will:
118
+
119
+ 1. Extract evenly spaced frames from the video into a folder like `movie_frames/`
120
+ 2. Run pupil segmentation and diameter estimation on those frames
121
+ 3. Save the results (CSV + plot) into `movie_result/`
122
+
123
+ To calculate pupil-center position and velocity from every encoded frame, add
124
+ `--calculate_velocity` and provide the actual acquisition rate when it differs
125
+ from the video playback rate:
126
+
127
+ ```bash
128
+ run-pupil-analysis \
129
+ --video_path data/mouse1.avi \
130
+ --calculate_velocity \
131
+ --acquisition_fps 33.3333333333
132
+ ```
133
+
134
+ Velocity mode calculates timestamps from the original source-frame index and
135
+ the acquisition rate. It does not assume that the FPS stored in the video
136
+ container always represents experimental time.
137
+
138
+ For the end-to-end methodology—from segmentation probabilities through pupil-center quality control and velocity—see [Segmentation-To-Velocity Method](project_overview.md#segmentation-to-velocity-method).
139
+
140
+ ## Try the Included Sample Data
141
+
142
+ The repository includes a compact set of real images and hand-labeled masks under [`sample_data/`](sample_data/README.md). It supports clone-and-run checks of uncropped-frame inference, overlays, paired training data, augmentation, and a 31-frame pupil-velocity sequence.
143
+
144
+ ```bash
145
+ run-pupil-analysis \
146
+ --image_dir sample_data/velocity_frames \
147
+ --result_dir results/sample_velocity \
148
+ --output_mask_dir results/sample_velocity/overlays \
149
+ --calculate_velocity \
150
+ --acquisition_fps 97
151
+ ```
152
+
153
+ The fixture is intended for workflow exploration and debugging, not scientific model evaluation or useful model training. See the [sample-data guide](sample_data/README.md) for the uncropped-frame and training examples.
154
+
155
+ ---
156
+
157
+ ## ⚙️ Key Arguments
158
+
159
+ | Argument | Description |
160
+ |---------------------|-------------------------------------------------------------------------------------------------------------------|
161
+ | `--video_path` | Path to the input video file. If provided, frames will automatically be extracted before analysis. |
162
+ | `--out_dir` | Optional. Directory to save extracted frames. If not given, defaults to `<video_stem>_frames/` next to the video. |
163
+ | `--image_dir` | Optional alternative to `--video_path`. Use this if you already have extracted PNG frames. |
164
+ | `--result_dir` | Optional. Directory to save the CSV and plot outputs. If not given, defaults to `<video_stem>_result/` for video input and `<image_dir>_result/` for `--image_dir` input. |
165
+ | `--checkpoint` | Optional. Path to a custom model checkpoint. If not provided, the packaged checkpoint is used. |
166
+ | `--output_mask_dir` | Optional. If provided, saves translucent confidence-heatmap overlays for threshold-passing pupil pixels. Yellow is closest to the prediction threshold, orange is intermediate, and red is near-perfect confidence. |
167
+ | `--extraction_fps` | Optional. Specifies the number of frames per second at which to extract the frames from the video (default: 5). If `--max_frames` is provided, and if the number of frames to be extracted at `--extraction_fps` would exceed `--max_frames`, then the actual `--extraction_fps` will be automatically reduced so that `--max_frames` number of frames will be extracted. |
168
+ | `--max_frames` | Optional. Limits the maximum number of frames to extract from a video (default: 10,000). Useful for long recordings. |
169
+ | `--pred_thresh` | Optional. Ranging from 0 to 1, it specifies the confidence threshold for classifying a pixel as belonging to the pupil. For example, a value of 0.7 means that a pixel will be classified as a pupil pixel only if model confidence exceeds 0.7. Increase it if the resulting segmentation overpredicts the pupil; reduce it if the resulting segmentation only finds part of the pupil. |
170
+ | `--calculate_velocity` | Optional. Analyzes every encoded source frame and appends pupil-center, speed, and segmentation-quality fields and plot panels to the unified analysis outputs. |
171
+ | `--num_workers` | Optional. Number of dataloader worker processes (default: up to 4, capped by CPU count). Use `0` to load frames in the main process, which is often faster for short recordings. |
172
+ | `--acquisition_fps` | Actual experimental sampling rate used for timestamps and velocity. In velocity mode this is required with `--image_dir`; with video input it defaults to the video header rate when omitted. |
173
+
174
+ ---
175
+
176
+ ## 💡 Examples
177
+
178
+ **From a video (auto frame extraction):**
179
+ ```bash
180
+ run-pupil-analysis --video_path data/mouse1.avi
181
+ ```
182
+
183
+ **From an existing folder of frames:**
184
+ ```bash
185
+ run-pupil-analysis --image_dir data/mouse1_frames
186
+ ```
187
+
188
+ **With custom output locations and segmentation masks:**
189
+ ```bash
190
+ run-pupil-analysis \
191
+ --video_path data/mouse1.avi \
192
+ --out_dir data/frames_mouse1 \
193
+ --result_dir data/results_mouse1 \
194
+ --output_mask_dir data/masks_mouse1
195
+ ```
196
+
197
+ ---
198
+
199
+ ## 🐍 Python API
200
+
201
+ Everything the CLI does is available from Python, which is usually more convenient
202
+ inside a notebook or a larger analysis script. The results come back as a DataFrame,
203
+ so there is no need to read the CSV back in.
204
+
205
+ ```python
206
+ from mouse_pupil_analysis import analyze_video
207
+
208
+ result = analyze_video("data/mouse1.avi")
209
+ print(result.analysis_table.head())
210
+ print(result.csv_path, result.plot_path)
211
+ ```
212
+
213
+ Velocity mode and every CLI flag are keyword arguments:
214
+
215
+ ```python
216
+ result = analyze_video(
217
+ "data/mouse1.avi",
218
+ calculate_velocity=True,
219
+ acquisition_fps=33.3333333333,
220
+ output_mask_dir="data/masks_mouse1",
221
+ )
222
+
223
+ usable = result.analysis_table.query("tracking_status != 'invalid'")
224
+ print(f"{len(usable)} of {len(result.analysis_table)} frames usable")
225
+ ```
226
+
227
+ To start from frames you already extracted, use `analyze_frames` instead:
228
+
229
+ ```python
230
+ from mouse_pupil_analysis import analyze_frames
231
+
232
+ result = analyze_frames(
233
+ "data/mouse1_frames",
234
+ calculate_velocity=True,
235
+ acquisition_fps=33.3333333333,
236
+ )
237
+ ```
238
+
239
+ `result` is an `AnalysisResult` with these fields:
240
+
241
+ | Field | Description |
242
+ |---|---|
243
+ | `analysis_table` | The same compact table written to CSV, as a DataFrame. |
244
+ | `csv_path`, `plot_path` | Locations of the written outputs. |
245
+ | `tracking_dataframe` | Detailed per-frame quality evidence in velocity mode, otherwise `None`. Retains raw centers, component areas, confidence, circularity, and temporal-area calculations that the compact table omits. |
246
+ | `image_frames` | Frame metadata linking each image name to its source-frame index. |
247
+
248
+ For repeated runs with shared settings, build an `AnalysisConfig` once and pass it to
249
+ `run_analysis`:
250
+
251
+ ```python
252
+ from mouse_pupil_analysis import AnalysisConfig, run_analysis
253
+
254
+ for video in Path("data").glob("*.avi"):
255
+ run_analysis(AnalysisConfig(video_path=video, pred_thresh=0.75))
256
+ ```
257
+
258
+ Library code logs rather than prints, so it stays quiet by default. To see the same
259
+ progress messages the CLI shows:
260
+
261
+ ```python
262
+ import logging
263
+ logging.basicConfig(level=logging.INFO)
264
+ ```
265
+
266
+ ---
267
+
268
+ ## 📦 Output Files
269
+
270
+ After running, you’ll typically find:
271
+
272
+ | File | Description |
273
+ |------|--------------|
274
+ | `*_pupil_analysis.csv` | Unified table containing `image_name` and pupil diameter in both model and input-image pixels. Velocity mode appends timestamp, accepted x/y center, speed, three-state tracking status, and a concise quality reason. Generated image names contain the one-based source-frame number. |
275
+ | `*_pupil_analysis.png` | Unified frame-indexed plot. Velocity mode appends x/y center, speed, and valid/warning/invalid quality-control panels below pupil diameter. |
276
+ | *(optional)* Mask images in `output_mask_dir` | PNGs with a translucent yellow-orange-red confidence heatmap over threshold-passing pupil pixels. Velocity mode also marks the raw pupil center with a thin translucent cross: cyan for accepted candidates and yellow for rejected candidates. |
277
+
278
+ ### Units
279
+
280
+ Pupil diameter is reported twice, in two different units:
281
+
282
+ - `estimated_pupil_diameter` is measured in the 148 x 148 model image. Because every
283
+ frame is rescaled to that size, this value is **not comparable between recordings**
284
+ with different resolution or cropping. It is kept for continuity with earlier results.
285
+ - `pupil_diameter_input_pixels` inverts the resize-and-pad geometry to express the same
286
+ measurement at the scale of **the image you supplied**. With `--video_path` that is the
287
+ source video frame. With `--image_dir` it is whatever you prepared: if your frames were
288
+ already cropped or resized to 148 x 148, this column equals `estimated_pupil_diameter`.
289
+
290
+ Both are equivalent-circle diameters: the diameter of a circle whose area matches the
291
+ segmented pupil mask, `sqrt(4 / pi * area)`.
292
+
293
+ Neither column is calibrated. `pupil_diameter_input_pixels` removes the model's rescaling,
294
+ but two recordings still only compare directly if their optics and working distance match.
295
+ Otherwise apply your own per-recording scale factor.
296
+
297
+ Pupil-center coordinates and speed use the same input-image pixel scale as
298
+ `pupil_diameter_input_pixels`: the source video frame with `--video_path`, and
299
+ whatever you supplied with `--image_dir`. The x coordinate increases to the right
300
+ and the y coordinate increases downward, and speed is in input-image pixels per
301
+ second. The same calibration caveat applies, so speeds are only directly
302
+ comparable between recordings whose optics and working distance match.
303
+
304
+ Neither unit is physical. Converting to millimeters requires a scale factor from your
305
+ own optics, which this package does not attempt to infer.
306
+
307
+ The compact analysis CSV reports `tracking_status` as `valid`, `warning`, or
308
+ `invalid`, with `quality_reason` identifying suspicious or rejected frames.
309
+ Published center and speed fields are left empty when segmentation is rejected.
310
+ Speed is also left empty when either adjacent frame is invalid or when source
311
+ frames are not consecutive; the pipeline does not interpolate across these
312
+ gaps. A warning remains usable, such as extra foreground components when the
313
+ selected pupil component is still acceptable.
314
+
315
+ ---
316
+
317
+ ## 🧩 Typical Folder Structure
318
+
319
+ ```
320
+ movie.avi
321
+ movie_frames/
322
+ movie_00001.png
323
+ movie_00002.png
324
+ ...
325
+ movie_result/
326
+ movie_pupil_analysis.csv
327
+ movie_pupil_analysis.png
328
+ ```
329
+
330
+ ---
331
+
332
+ ## Citation
333
+
334
+ If you use this software in a paper or other scholarly work, please cite the version you used. GitHub renders citation metadata from [`CITATION.cff`](CITATION.cff), and the “Cite this repository” button produces BibTeX directly.
335
+
336
+ Recommended citation:
337
+
338
+ > Yue Zhao. *mouse-pupil-analysis: Automated mouse pupil segmentation, diameter, and pupil-center velocity analysis using UNet*. Version 0.2.0. https://github.com/yzhaoinuw/mouse-pupil-analysis
339
+
340
+ Zenodo archiving is enabled, but no DOI exists until the first GitHub Release is published; see [`RELEASING.md`](RELEASING.md). Once Zenodo processes that release, cite the DOI of the specific version you ran so your analysis stays reproducible against that exact code. Until then, cite the version number and commit. See [`CHANGELOG.md`](CHANGELOG.md) for what changed between versions.
341
+
342
+ ## License
343
+
344
+ This project is released under the MIT License. See [`LICENSE`](LICENSE).
345
+
346
+ ---
347
+
348
+ ## Developer Notes
349
+
350
+ ### Model Training
351
+
352
+ The complete data-preparation, augmentation, fresh-training, fine-tuning, and checkpoint-promotion workflow is documented in [`training/README.md`](training/README.md).
353
+
354
+ #### Making Training Data
355
+ Create two folders in *mouse-pupil-analysis/*, *images_train/* and *masks_train/* if you haven't. Place your training images in *images_train/*. Once you have done this once, you can just add new training images to *images_train/*.
356
+ 1. In Terminal/Anaconda Powershell Prompt, activate your project environment, then run `labelme.exe`
357
+ to open the labelme interface to label images.
358
+ 2. After you are done, **labelme** should have saved your labels as json files in *images_train/* along with your training images. Now run `python .\training\labelme_json2png.py`, which will create the masks (png files) and move them to *masks_train/*.
359
+ 3. To create the validation set, create *images_validation/* and *masks_validation/* and then follow the same steps above, but remember to change **dataset_type** in **training/labelme_json2png.py** accordingly.
360
+ 4. To start training the model, run `python .\training\run_train.py`. You can modify the hyperparameters in **training/run_train.py** as needed.