mesofield 0.3.2b0__py3-none-any.whl
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.
- docs/_static/custom.css +40 -0
- docs/_static/favicon.png +0 -0
- docs/_static/logo.png +0 -0
- docs/api/index.md +70 -0
- docs/conf.py +200 -0
- docs/developer_guide.md +303 -0
- docs/index.md +25 -0
- docs/tutorial.md +4 -0
- docs/user_guide.md +172 -0
- examples/teensy_pulse_generator.py +320 -0
- experiments/pipeline_demo/experiment.json +24 -0
- experiments/pipeline_demo/hardware.yaml +23 -0
- experiments/pipeline_demo/procedure.py +50 -0
- experiments/two_cam_demo/experiment.json +24 -0
- experiments/two_cam_demo/hardware.yaml +58 -0
- experiments/two_cam_demo/load_dataset.py +213 -0
- experiments/two_cam_demo/procedure.py +87 -0
- external/video-codecs/openh264-1.8.0-win64.dll +0 -0
- mesofield/__init__.py +45 -0
- mesofield/__main__.py +11 -0
- mesofield/_version.py +24 -0
- mesofield/base.py +750 -0
- mesofield/cli/__init__.py +57 -0
- mesofield/cli/_richhelp.py +100 -0
- mesofield/cli/acquire.py +254 -0
- mesofield/cli/datakit.py +165 -0
- mesofield/cli/process.py +376 -0
- mesofield/cli/rig.py +108 -0
- mesofield/cli/tools.py +347 -0
- mesofield/config.py +751 -0
- mesofield/data/__init__.py +23 -0
- mesofield/data/batch.py +633 -0
- mesofield/data/manager.py +388 -0
- mesofield/data/writer.py +289 -0
- mesofield/datakit/__init__.py +44 -0
- mesofield/datakit/__main__.py +35 -0
- mesofield/datakit/_utils/_logger.py +5 -0
- mesofield/datakit/_version.py +141 -0
- mesofield/datakit/config.py +50 -0
- mesofield/datakit/core.py +783 -0
- mesofield/datakit/datamodel.py +200 -0
- mesofield/datakit/discover.py +124 -0
- mesofield/datakit/explore.py +651 -0
- mesofield/datakit/notebooks/pupil_dlc.ipynb +2445 -0
- mesofield/datakit/profile.py +535 -0
- mesofield/datakit/shell.py +83 -0
- mesofield/datakit/sources/__init__.py +65 -0
- mesofield/datakit/sources/analysis/mesomap.py +194 -0
- mesofield/datakit/sources/analysis/mesoscope.py +77 -0
- mesofield/datakit/sources/analysis/pupil.py +246 -0
- mesofield/datakit/sources/behavior/__init__.py +0 -0
- mesofield/datakit/sources/behavior/dataqueue.py +281 -0
- mesofield/datakit/sources/behavior/psychopy.py +364 -0
- mesofield/datakit/sources/behavior/treadmill.py +323 -0
- mesofield/datakit/sources/behavior/wheel.py +277 -0
- mesofield/datakit/sources/camera/mesoscope.py +32 -0
- mesofield/datakit/sources/camera/metadata_json.py +130 -0
- mesofield/datakit/sources/camera/pupil.py +28 -0
- mesofield/datakit/sources/camera/suite2p.py +547 -0
- mesofield/datakit/sources/register.py +204 -0
- mesofield/datakit/sources/session/config.py +130 -0
- mesofield/datakit/sources/session/notes.py +63 -0
- mesofield/datakit/sources/session/timestamps.py +58 -0
- mesofield/datakit/timeline.py +306 -0
- mesofield/devices/__init__.py +42 -0
- mesofield/devices/base.py +498 -0
- mesofield/devices/base_camera.py +295 -0
- mesofield/devices/cameras.py +740 -0
- mesofield/devices/daq.py +151 -0
- mesofield/devices/encoder.py +384 -0
- mesofield/devices/mocks.py +275 -0
- mesofield/devices/psychopy_device.py +455 -0
- mesofield/devices/subprocesses/__init__.py +0 -0
- mesofield/devices/subprocesses/psychopy.py +133 -0
- mesofield/devices/treadmill.py +318 -0
- mesofield/engines.py +380 -0
- mesofield/gui/Mesofield_icon.png +0 -0
- mesofield/gui/__init__.py +76 -0
- mesofield/gui/config_wizard.py +724 -0
- mesofield/gui/controller.py +535 -0
- mesofield/gui/dynamic_controller.py +78 -0
- mesofield/gui/maingui.py +427 -0
- mesofield/gui/mdagui.py +285 -0
- mesofield/gui/qt_device_adapter.py +109 -0
- mesofield/gui/speedplotter.py +152 -0
- mesofield/gui/theme.py +445 -0
- mesofield/gui/tiff_viewer.py +1050 -0
- mesofield/gui/viewer.py +691 -0
- mesofield/hardware.py +549 -0
- mesofield/playback.py +1298 -0
- mesofield/processing/__init__.py +12 -0
- mesofield/processing/runner.py +237 -0
- mesofield/processors/__init__.py +13 -0
- mesofield/processors/base.py +287 -0
- mesofield/processors/frame_mean.py +19 -0
- mesofield/protocols.py +378 -0
- mesofield/scaffold/__init__.py +34 -0
- mesofield/scaffold/experiment.py +400 -0
- mesofield/scaffold/rigs.py +121 -0
- mesofield/signals.py +85 -0
- mesofield/utils/__init__.py +0 -0
- mesofield/utils/_logger.py +156 -0
- mesofield/utils/retrofit.py +309 -0
- mesofield/utils/utils.py +217 -0
- mesofield-0.3.2b0.dist-info/METADATA +178 -0
- mesofield-0.3.2b0.dist-info/RECORD +111 -0
- mesofield-0.3.2b0.dist-info/WHEEL +5 -0
- mesofield-0.3.2b0.dist-info/entry_points.txt +2 -0
- mesofield-0.3.2b0.dist-info/licenses/LICENSE +21 -0
- mesofield-0.3.2b0.dist-info/top_level.txt +6 -0
- scripts/bench_frame_processor.py +103 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mesofield
|
|
3
|
+
Version: 0.3.2b0
|
|
4
|
+
Summary: Mesofield is an open-source image acquisition Python software package build for the Sipe Laboratory at Pennsylvania State University.
|
|
5
|
+
Author: Jacob Gronemeyer
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 Gronemeyer
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/Gronemeyer/mesofield/
|
|
29
|
+
Project-URL: Repository, https://github.com/Gronemeyer/mesofield/
|
|
30
|
+
Project-URL: Issues, https://github.com/Gronemeyer/mesofield/issues
|
|
31
|
+
Project-URL: Documentation, https://gronemeyer.github.io/mesofield/
|
|
32
|
+
Keywords: imaging,microscopy,acquisition,neuroscience
|
|
33
|
+
Classifier: Development Status :: 4 - Beta
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Scientific/Engineering
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
42
|
+
Requires-Python: >=3.10
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
License-File: LICENSE
|
|
45
|
+
Requires-Dist: annotated-types
|
|
46
|
+
Requires-Dist: click
|
|
47
|
+
Requires-Dist: ipykernel
|
|
48
|
+
Requires-Dist: ipython
|
|
49
|
+
Requires-Dist: jupyter_client
|
|
50
|
+
Requires-Dist: jupyter_core
|
|
51
|
+
Requires-Dist: loguru
|
|
52
|
+
Requires-Dist: markdown-it-py
|
|
53
|
+
Requires-Dist: matplotlib
|
|
54
|
+
Requires-Dist: mesokit-schema
|
|
55
|
+
Requires-Dist: nidaqmx
|
|
56
|
+
Requires-Dist: numpy
|
|
57
|
+
Requires-Dist: packaging
|
|
58
|
+
Requires-Dist: pandas
|
|
59
|
+
Requires-Dist: parso
|
|
60
|
+
Requires-Dist: pillow
|
|
61
|
+
Requires-Dist: platformdirs
|
|
62
|
+
Requires-Dist: psygnal
|
|
63
|
+
Requires-Dist: pyaml
|
|
64
|
+
Requires-Dist: opencv-python
|
|
65
|
+
Requires-Dist: pymmcore
|
|
66
|
+
Requires-Dist: pymmcore-plus
|
|
67
|
+
Requires-Dist: pymmcore-widgets
|
|
68
|
+
Requires-Dist: PyQt6
|
|
69
|
+
Requires-Dist: PyQt6-Qt6
|
|
70
|
+
Requires-Dist: PyQt6_sip
|
|
71
|
+
Requires-Dist: pyqtgraph
|
|
72
|
+
Requires-Dist: pyserial
|
|
73
|
+
Requires-Dist: python-dateutil
|
|
74
|
+
Requires-Dist: pytz
|
|
75
|
+
Requires-Dist: pywin32; sys_platform == "win32"
|
|
76
|
+
Requires-Dist: pyzmq
|
|
77
|
+
Requires-Dist: qtconsole
|
|
78
|
+
Requires-Dist: rich
|
|
79
|
+
Requires-Dist: setuptools
|
|
80
|
+
Requires-Dist: tifffile
|
|
81
|
+
Requires-Dist: typer
|
|
82
|
+
Requires-Dist: typer-slim
|
|
83
|
+
Requires-Dist: typing_extensions
|
|
84
|
+
Requires-Dist: useq-schema
|
|
85
|
+
Requires-Dist: wheel
|
|
86
|
+
Provides-Extra: test
|
|
87
|
+
Requires-Dist: pytest; extra == "test"
|
|
88
|
+
Requires-Dist: coverage; extra == "test"
|
|
89
|
+
Requires-Dist: flake8; extra == "test"
|
|
90
|
+
Requires-Dist: black; extra == "test"
|
|
91
|
+
Requires-Dist: isort; extra == "test"
|
|
92
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
93
|
+
Requires-Dist: mypy; extra == "test"
|
|
94
|
+
Requires-Dist: gitchangelog; extra == "test"
|
|
95
|
+
Provides-Extra: docs
|
|
96
|
+
Requires-Dist: sphinx>=7; extra == "docs"
|
|
97
|
+
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
|
98
|
+
Requires-Dist: myst-parser; extra == "docs"
|
|
99
|
+
Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
100
|
+
Requires-Dist: sphinx-design; extra == "docs"
|
|
101
|
+
Dynamic: license-file
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
__ __ ______ ______ ______ ______ __ ______ __ _____
|
|
105
|
+
/\ "-./ \ /\ ___\ /\ ___\ /\ __ \ /\ ___\ /\ \ /\ ___\ /\ \ /\ __-.
|
|
106
|
+
\ \ \-./\ \ \ \ __\ \ \___ \ \ \ \/\ \ \ \ __\ \ \ \ \ \ __\ \ \ \____ \ \ \/\ \
|
|
107
|
+
\ \_\ \ \_\ \ \_____\ \/\_____\ \ \_____\ \ \_\ \ \_\ \ \_____\ \ \_____\ \ \____-
|
|
108
|
+
\/_/ \/_/ \/_____/ \/_____/ \/_____/ \/_/ \/_/ \/_____/ \/_____/ \/____/
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Mesofield is a PyQt6-based framework for running real-time, multi-camera
|
|
112
|
+
neuroscience experiments. It coordinates hardware via serial connections
|
|
113
|
+
and MicroManager (through [pymmcore-plus](https://pymmcore-plus.github.io/pymmcore-plus/)
|
|
114
|
+
custom `MDAEngine`s and multi-`CMMCorePlus` instancing) and manages
|
|
115
|
+
experiment configuration, acquisition orchestration, and data logging.
|
|
116
|
+
The project is aimed at laboratory use and is not a full production
|
|
117
|
+
package; some specialised knowledge of device hardware and
|
|
118
|
+
MicroManager device configuration is necessary to get started.
|
|
119
|
+
|
|
120
|
+
<img width="2454" height="1592" alt="Mesofield acquisition window" src="https://github.com/user-attachments/assets/151196ab-2d74-4644-85b7-c4facf3b779a" />
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Documentation
|
|
125
|
+
|
|
126
|
+
Documentation lives at **[gronemeyer.github.io/mesofield](https://gronemeyer.github.io/mesofield/)**
|
|
127
|
+
and is split by audience:
|
|
128
|
+
|
|
129
|
+
- **[Tutorial](https://gronemeyer.github.io/mesofield/tutorial.html)** —
|
|
130
|
+
the fastest path from a fresh conda env to a working acquisition on
|
|
131
|
+
your hardware.
|
|
132
|
+
- **[User Guide](https://gronemeyer.github.io/mesofield/user_guide.html)** —
|
|
133
|
+
for experimenters running acquisitions: launching the GUI, writing
|
|
134
|
+
`experiment.json`, interpreting the on-disk output.
|
|
135
|
+
- **[Developer Guide](https://gronemeyer.github.io/mesofield/developer_guide.html)** —
|
|
136
|
+
for developers extending mesofield: custom devices, `Procedure`
|
|
137
|
+
subclasses, frame processors, threading models.
|
|
138
|
+
- **[API Reference](https://gronemeyer.github.io/mesofield/api/index.html)** —
|
|
139
|
+
auto-generated from docstrings.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Quick start
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
conda create -n mesofield python=3.12 -y
|
|
147
|
+
conda activate mesofield
|
|
148
|
+
pip install -e .
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Launch an acquisition:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
mesofield launch path/to/experiment.json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Scaffold a new experiment:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
mesofield new my-experiment
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
For end-to-end setup, follow the
|
|
164
|
+
[Tutorial](https://gronemeyer.github.io/mesofield/tutorial.html).
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## System requirements
|
|
169
|
+
|
|
170
|
+
Tested on Windows 10/11. For multi-camera acquisition with large files
|
|
171
|
+
we recommend ≥ 32 GB RAM, a 12th-gen Intel i7 or equivalent, and fast
|
|
172
|
+
local NVMe storage for the experiment directory.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT — see `LICENSE`.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
docs/conf.py,sha256=28qzRsFqHtGuxwMMnO61Z3342QWuAFf-Lot3Ce-4ccw,5797
|
|
2
|
+
docs/developer_guide.md,sha256=VwL0-VwSGDlJqn8WtfFNKkKIdWDJpbR-rCnMm8sDWmM,10092
|
|
3
|
+
docs/index.md,sha256=MZmUXpcVBVRzekQ16L8ptgbD-2c8MxhFGk9pX0rYK7k,231
|
|
4
|
+
docs/tutorial.md,sha256=O02adi_EwtThPnGZPm5PFq8SfkJItsyvFsKum68CX7s,44
|
|
5
|
+
docs/user_guide.md,sha256=fkkPPO2B91ptc8FU2YEN9ne-06kin_3WQHAxToivkkU,5456
|
|
6
|
+
docs/_static/custom.css,sha256=GghYxBc-OUBS2ZlzRbpFdlWpoJmwdRgv6IqOAx4abPM,1143
|
|
7
|
+
docs/_static/favicon.png,sha256=wID6OeeUAaa9Z3nRDViMwodadPUyut6P1PY_ZqrnO-M,5521
|
|
8
|
+
docs/_static/logo.png,sha256=v-vcal3qIT7UQ-fFoVKZxmqoSnSx9gm3fUBOvjDOa5c,3307179
|
|
9
|
+
docs/api/index.md,sha256=M6ei1sQoAD5vV7F7YdSkTprJIerEch2cOIpqMKXslDY,1419
|
|
10
|
+
examples/teensy_pulse_generator.py,sha256=N_pCd-zy-58dvV_bd0gduzrbSEkNPp5dcmAUq4w820o,11809
|
|
11
|
+
experiments/pipeline_demo/experiment.json,sha256=i0TxmPDbQMUKzA1HSQZLPedwJ5p4peprCuxAfeou9GM,510
|
|
12
|
+
experiments/pipeline_demo/hardware.yaml,sha256=RZwkcwUNtxDNDkNZdYBiqjNodBEEQz9yc2RAZp1A9qU,766
|
|
13
|
+
experiments/pipeline_demo/procedure.py,sha256=Jf6NQKDMzDmbafPUZ6HvZJWy-v0IcecHWp-JePoIfKk,1794
|
|
14
|
+
experiments/two_cam_demo/experiment.json,sha256=d_6sJQO0tamUtFcD_96arwUu6jlawzzp7RuF9dHuHks,500
|
|
15
|
+
experiments/two_cam_demo/hardware.yaml,sha256=RueqtivtSLNErUbZZFkFv_Eu_SxTt7TJf07REjVe8Nw,1670
|
|
16
|
+
experiments/two_cam_demo/load_dataset.py,sha256=xUfIbLKLxOhYWxE0gkzDz5ueVIQztpinW4M95qflkAM,7833
|
|
17
|
+
experiments/two_cam_demo/procedure.py,sha256=_aCodNaMV38K1-TQdwEpSKOBmsrTSkhdrhpaOmgNohI,2811
|
|
18
|
+
external/video-codecs/openh264-1.8.0-win64.dll,sha256=46XPBbZzoX6_6VrGtHlgfPTfIon-Sm1fPT_wmqj1YZI,825160
|
|
19
|
+
mesofield/__init__.py,sha256=PNApkSEBeOKDn8H36K82ypujeE_z3RJqwqUdO9BcynU,1598
|
|
20
|
+
mesofield/__main__.py,sha256=LQd6RQOjvkGRKNjYt0axPM8K1lpIy7e09HXFDeCDtAQ,322
|
|
21
|
+
mesofield/_version.py,sha256=8vQ-PW_RN5R5Sm30qpmcKIOz6bUBKcwPZ4KWfmHoUhA,528
|
|
22
|
+
mesofield/base.py,sha256=eZDZ2CSE-gYkhd5qFqtNyoYNpbcvI0t8Xaz1uOh-hzk,30882
|
|
23
|
+
mesofield/config.py,sha256=uVxGvOf9_c20fq7J71SAQz_jkNws6n5LCKdEJqIhiP0,29665
|
|
24
|
+
mesofield/engines.py,sha256=LH5Jv-9rpQAV3xGxzZeB2hSYEVQ0QJM3TEnLbUIoQ5M,17385
|
|
25
|
+
mesofield/hardware.py,sha256=1BvZGrN5Xkl550C5cOA45OiwbwcmxEVhzHrjfIhVW6w,23056
|
|
26
|
+
mesofield/playback.py,sha256=_kmb7hqodXlvl5ZhJYWq6UpiIsQltpOQrzRB54DRzkY,48359
|
|
27
|
+
mesofield/protocols.py,sha256=fWtBRBDcj6GRDGUJH8b2fTLvVfFbyRT_2oONrjQzs4w,11173
|
|
28
|
+
mesofield/signals.py,sha256=FnL-cXwTJDp9kbO5shqrWPewKk3njlqGWJyRJ6ODZz4,3191
|
|
29
|
+
mesofield/cli/__init__.py,sha256=W0_C7bRJMuBCBLU7lzvjfs_MJDXZqVxK4P-wdVID9U8,1521
|
|
30
|
+
mesofield/cli/_richhelp.py,sha256=nGs_dUnanY4O7Chyw-iw6ajOdA1K-D86CE1xl4oCw6Q,3455
|
|
31
|
+
mesofield/cli/acquire.py,sha256=omtRtH2n3TKNthdmWtCgUVUvpy8YWBvstQQr1IAar3I,9796
|
|
32
|
+
mesofield/cli/datakit.py,sha256=fS-tGBJIpuSQPgNtINYQiKVFJY6PSeTl2OspVinP79Q,6668
|
|
33
|
+
mesofield/cli/process.py,sha256=sjlRHNfSr0SdrbYy1h-MANN8jr5vtsE-AUxQQLUDMk4,14798
|
|
34
|
+
mesofield/cli/rig.py,sha256=nsRYQTYFhqjFr5pazEnXAjoywkhUobxyo94f63vV1kE,3400
|
|
35
|
+
mesofield/cli/tools.py,sha256=st3YE4LmAMxRxalSIj9Pb0FJPNO2U0d_F3S7dXaFX9o,12446
|
|
36
|
+
mesofield/data/__init__.py,sha256=n2IWLLEAltoYNHturPUqpXG581oOZ4ViJZwzn7efnu0,850
|
|
37
|
+
mesofield/data/batch.py,sha256=6BwlCdq_rnIg19p4glZ2bMLdyaAPQmgDYXuhpDhMAK0,23543
|
|
38
|
+
mesofield/data/manager.py,sha256=OL-LZfx7oosQtDJaxiZK2H7Z1Zu1BcpsZWY8_ga0zbI,15029
|
|
39
|
+
mesofield/data/writer.py,sha256=B3W5CloTmoeqGsLCnHFHWLkppDRsGyviJvxCt2_RDxw,12084
|
|
40
|
+
mesofield/datakit/__init__.py,sha256=q_NUyMwNpRPB1ETlrKKydTGjVI0I0_cc5FOB1a5lvxw,1229
|
|
41
|
+
mesofield/datakit/__main__.py,sha256=J7oYsPGBJDL99U2CSx4lt7zi-5pChmTsegsXCJzDhoM,953
|
|
42
|
+
mesofield/datakit/_version.py,sha256=P1-D0rmwXjXyZsIU_ebUw3WdyW_d3Ni8pkBY5yQGziU,4445
|
|
43
|
+
mesofield/datakit/config.py,sha256=LzD0WttrIb44LM9tlcnK3cqvaiWinudKYRUFTt37y2w,1359
|
|
44
|
+
mesofield/datakit/core.py,sha256=YDNMxgwZDtXso4SvYrZzVfe5F-QKH7lH9BG8IsXrkjM,29420
|
|
45
|
+
mesofield/datakit/datamodel.py,sha256=NpdoAh2tscDNeTRfO0s2Wzx1CoQjY7AGymamFUrfd24,6909
|
|
46
|
+
mesofield/datakit/discover.py,sha256=0iGwnwnKthw2lmSQ_y6aDwhK1Z_3kG5AtWqtYHoWz_Y,4317
|
|
47
|
+
mesofield/datakit/explore.py,sha256=nGJ5OVMnU-uGlH0ZCQt1Opjlt9LI4T8Qf7SCh-w8Xu0,22348
|
|
48
|
+
mesofield/datakit/profile.py,sha256=sVppbHBiIu4H8ybnKmxggfpZCt2wHryklx56CNekanM,20147
|
|
49
|
+
mesofield/datakit/shell.py,sha256=BivWC-tPEAKnnPPlcl6nA-Jbn1QRopezSOJMQJuPrk0,2736
|
|
50
|
+
mesofield/datakit/timeline.py,sha256=VIm0_vmk2SvYqk9JZt9gcFTb5RDMr_as3NF_nYLTHKM,10472
|
|
51
|
+
mesofield/datakit/_utils/_logger.py,sha256=G5zHT8QlDCWZgdRZLD290WY1QdskJLy0BLEPBeU8m80,232
|
|
52
|
+
mesofield/datakit/notebooks/pupil_dlc.ipynb,sha256=ujk_XZe3aJQFHIXx3VtuQuV3huZPgndZS_-eZbJxviw,174264
|
|
53
|
+
mesofield/datakit/sources/__init__.py,sha256=hoNoMtyPTSnkSkxDHeilXrp-Zcfp9pvAbr_VZp8yVyc,2005
|
|
54
|
+
mesofield/datakit/sources/register.py,sha256=uqpOrXeFWKl5Pdvlhkwp-YC6ya82IDo_-bAFtH0xYSg,7572
|
|
55
|
+
mesofield/datakit/sources/analysis/mesomap.py,sha256=6VRonqRHB-JgoNujeBz_H5HXRiW9UiIp9In0bLxbWXE,5818
|
|
56
|
+
mesofield/datakit/sources/analysis/mesoscope.py,sha256=dLn_0G-63qzy7o8X-hNsyTTbXdNnOFHA6iVT_8e9P10,2499
|
|
57
|
+
mesofield/datakit/sources/analysis/pupil.py,sha256=Vltfu2Lzpj0HSPr2CbrVcNz5CMtQoIZYMvFDdETlehU,10136
|
|
58
|
+
mesofield/datakit/sources/behavior/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
|
+
mesofield/datakit/sources/behavior/dataqueue.py,sha256=hayM6CPNVPmTO6BHSAWHPEgl6fS5REYiHaVwpUjO3i0,11394
|
|
60
|
+
mesofield/datakit/sources/behavior/psychopy.py,sha256=r5CiETEfnGzpzK27tDwK6sg-8ecumtC2jMOiSTkHzlg,17554
|
|
61
|
+
mesofield/datakit/sources/behavior/treadmill.py,sha256=LM2xjiWdUdDDK42LVR6jTxRR6OteWFQU-hE3UrJtXzY,13100
|
|
62
|
+
mesofield/datakit/sources/behavior/wheel.py,sha256=ix25Dk4C8zFVsMEmAxLUsdvQGFaX8LyWMkBwJz6R74E,11379
|
|
63
|
+
mesofield/datakit/sources/camera/mesoscope.py,sha256=2epNdmHuDaU1mojLW4Oy0byG40iKJRmhJ7CSAs_89bM,975
|
|
64
|
+
mesofield/datakit/sources/camera/metadata_json.py,sha256=vcwPSuEAFQSDc0PGhiL-XZLq4aZBL3wjDN-M9FOg2yY,4953
|
|
65
|
+
mesofield/datakit/sources/camera/pupil.py,sha256=Z0BfXaI0ih4psD0eMtqVVAqVicnQ2in5WnuTBRO06AM,895
|
|
66
|
+
mesofield/datakit/sources/camera/suite2p.py,sha256=74-VUCyB-agb3E94ASi3ri8oL5j_v8FmS4aISm77h64,21374
|
|
67
|
+
mesofield/datakit/sources/session/config.py,sha256=yMUX4ev2ZJczn6baD0F7cMcmz3cPTfQC7rheLrnqbTM,4070
|
|
68
|
+
mesofield/datakit/sources/session/notes.py,sha256=AQTcQpQiGdVCjULJUnrjieYi3zonCg-6QagZqnn5ZK8,2202
|
|
69
|
+
mesofield/datakit/sources/session/timestamps.py,sha256=48Vimmg9NHHTf4pn7k1hkF9YdYm8gbbkHRr5uVHzgLM,1760
|
|
70
|
+
mesofield/devices/__init__.py,sha256=i3S6vfo-vs3nfilVA-t8zEoqr92JEx4GV7I-I1k9yb8,1139
|
|
71
|
+
mesofield/devices/base.py,sha256=Ammh4GyIgIEcW4EhHOf_dzKIN8q2SimL8kDcyOWCxQE,18883
|
|
72
|
+
mesofield/devices/base_camera.py,sha256=g3q9rWXB9l8TWmkk131YTG_4-deB-sj4OX9nyPuYxIs,13336
|
|
73
|
+
mesofield/devices/cameras.py,sha256=gQKkGyv8iiOl3bcJcpGik7bRnhXUytokdbnUqntMxnc,30938
|
|
74
|
+
mesofield/devices/daq.py,sha256=s9HZjP6WgQSwxhom3rUQ2DTJn3yqqcWrctEieXNP3Pw,5087
|
|
75
|
+
mesofield/devices/encoder.py,sha256=bfLefLJiw5TYHQ9T8aLrO9X_xaA1hDA_JDcfCQEexlQ,15721
|
|
76
|
+
mesofield/devices/mocks.py,sha256=DiZAuDnXyteQbdbM71WX30EGVa4vg7Xl1Hqjr2sWH9k,9676
|
|
77
|
+
mesofield/devices/psychopy_device.py,sha256=C-iXt5k_3fD0n97MowySAiXwvf6I1RCg8l6JGlp0_Zg,20127
|
|
78
|
+
mesofield/devices/treadmill.py,sha256=C8Bd5PTPdl-kWrrwo0zm3FyLSb805qQ62CPjXq_zzcc,12505
|
|
79
|
+
mesofield/devices/subprocesses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
|
+
mesofield/devices/subprocesses/psychopy.py,sha256=ogjlV3Z8SCt1UUpgUnHnzbtII3T4oklkxYELt6w3UO8,4779
|
|
81
|
+
mesofield/gui/Mesofield_icon.png,sha256=v-vcal3qIT7UQ-fFoVKZxmqoSnSx9gm3fUBOvjDOa5c,3307179
|
|
82
|
+
mesofield/gui/__init__.py,sha256=JaN3ucCS9oljWyMgDvSBEIIjLmm-Gqan63fFziFmJdM,2972
|
|
83
|
+
mesofield/gui/config_wizard.py,sha256=Xtg0FGRkS_XkIWjA15OyaRskKL8CurO0u60cio5BXzs,26306
|
|
84
|
+
mesofield/gui/controller.py,sha256=d59eBrKzm79ecWzzwPYNvqUXBRQTNt6QdOSkLSxBlLE,22956
|
|
85
|
+
mesofield/gui/dynamic_controller.py,sha256=-TW0hgzTz8JWck7BPkgTpFh3dd3ifd3PWH2esj-a0K0,3067
|
|
86
|
+
mesofield/gui/maingui.py,sha256=zmWDPxV9HyGJuu9ZnIzrCBIYhrhSr03J-GCP7P9UyeQ,18399
|
|
87
|
+
mesofield/gui/mdagui.py,sha256=8SWPiCfj7WeXnc614093m5sQ1lAFs0S7YKPWxZW3zRw,12333
|
|
88
|
+
mesofield/gui/qt_device_adapter.py,sha256=ArdQY4ViY4MdgEkTAO8cjNz7TOe-QvJx-RB87w8O4ec,3873
|
|
89
|
+
mesofield/gui/speedplotter.py,sha256=HInnc9-U9B9l184r2YeA2GO5C-d8Uspx3G2rGGf0xV0,5331
|
|
90
|
+
mesofield/gui/theme.py,sha256=AfGPpXW-UXjJ1yRFTWxvPJOF2K6VCrcYyklmmuBUf50,12575
|
|
91
|
+
mesofield/gui/tiff_viewer.py,sha256=jKJBYCXfdaamo3iMsHDUMwG2y-YHHkcIjbamGU4jj48,39855
|
|
92
|
+
mesofield/gui/viewer.py,sha256=1AO73-HsvWDePoOJdXg6TDJCShzsYDn_ONZNGhNFdTc,27919
|
|
93
|
+
mesofield/processing/__init__.py,sha256=NB8sq44fSHokcHCZHtfbmcTXXemDCnSjcqdklF0A0AI,493
|
|
94
|
+
mesofield/processing/runner.py,sha256=0F3k7tHwC9fhzwnr5lrTrHBIOFNwp9RJKD-a6Nhcbu8,8777
|
|
95
|
+
mesofield/processors/__init__.py,sha256=2kWdxGH3n9ujnkDKbzKZjkRt0TTnxnutMVr8Dp0bYRE,519
|
|
96
|
+
mesofield/processors/base.py,sha256=2JbE5PDAW7v1b624mb73d0J_5zMXVGpBAFCG5LNmHWM,10121
|
|
97
|
+
mesofield/processors/frame_mean.py,sha256=jDwLprmRuv60ZfZxnuaikWg4ZosS12m_81a8ViU11kY,465
|
|
98
|
+
mesofield/scaffold/__init__.py,sha256=kYmq5PQg0LEIsO2yIs2bIgoE0hi0Rs6FT7mOOwoe5F8,799
|
|
99
|
+
mesofield/scaffold/experiment.py,sha256=dcjjqfN0NZ1h1NduV2BcTxR2wJ1157eC-SGB5db-aFw,16078
|
|
100
|
+
mesofield/scaffold/rigs.py,sha256=TD6JVB_7i8-dYwo-F8kTtssR6YC5H66opfSRRd0arQY,4235
|
|
101
|
+
mesofield/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
102
|
+
mesofield/utils/_logger.py,sha256=U6Zcn-MPG7GrY3pS1THDt59mVx0Ql3Ky-27wgIePwCw,4423
|
|
103
|
+
mesofield/utils/retrofit.py,sha256=hr4yWWRxfHiUeLiq55cYZOJIKp1b9hzMowlCaKFMxQQ,11037
|
|
104
|
+
mesofield/utils/utils.py,sha256=mfrsHMob1-A8rMXN2qZ9XrdmTpIQiyL9HOuTkWRsxbQ,7516
|
|
105
|
+
mesofield-0.3.2b0.dist-info/licenses/LICENSE,sha256=K-JfzMZ1QmIaDcdcEHXi2Oq4K4AT092cqbQoy5LeR0o,1067
|
|
106
|
+
scripts/bench_frame_processor.py,sha256=m8rnBoBPUp_L5O0lZr3AP0MYUq-nfmC-5uFUVdgMcgQ,3317
|
|
107
|
+
mesofield-0.3.2b0.dist-info/METADATA,sha256=Uy99aQ_JFvWN32rkaLlU46uEXTJODicxFSa0xEgeFKQ,6653
|
|
108
|
+
mesofield-0.3.2b0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
109
|
+
mesofield-0.3.2b0.dist-info/entry_points.txt,sha256=nDsPDlUztjAGQC1awrNrSC4tnrxbpNYd4uL2lrfTc0s,48
|
|
110
|
+
mesofield-0.3.2b0.dist-info/top_level.txt,sha256=t_c9i9mTQRzaM345eXWVMqlGjyKXZgG23RYVPhZg0oU,53
|
|
111
|
+
mesofield-0.3.2b0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Gronemeyer
|
|
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,103 @@
|
|
|
1
|
+
"""Stress harness for :class:`mesofield.processors.FrameProcessor`.
|
|
2
|
+
|
|
3
|
+
Emits synthetic frames through ``DeviceSignals.frame`` at a target rate
|
|
4
|
+
with a configurable image size and (optional) artificial compute load,
|
|
5
|
+
then prints throughput, drop %, and EWMA / max compute time.
|
|
6
|
+
|
|
7
|
+
No real camera or Qt is required. Example::
|
|
8
|
+
|
|
9
|
+
python scripts/bench_frame_processor.py --size 512 --fps 60 --seconds 3
|
|
10
|
+
python scripts/bench_frame_processor.py --size 2048 --fps 120 \\
|
|
11
|
+
--extra-compute-ms 5 --seconds 5
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import time
|
|
18
|
+
from typing import Any, Optional
|
|
19
|
+
|
|
20
|
+
import numpy as np
|
|
21
|
+
|
|
22
|
+
from mesofield.processors import FrameMean
|
|
23
|
+
from mesofield.signals import DeviceSignals
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _FakeCamera:
|
|
27
|
+
def __init__(self, fps: float) -> None:
|
|
28
|
+
self.signals = DeviceSignals()
|
|
29
|
+
self.sampling_rate = fps
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _BenchMean(FrameMean):
|
|
33
|
+
"""FrameMean with an optional artificial compute delay."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, *args: Any, extra_compute_ms: float = 0.0, **kw: Any) -> None:
|
|
36
|
+
super().__init__(*args, **kw)
|
|
37
|
+
self._extra_s = extra_compute_ms / 1000.0
|
|
38
|
+
|
|
39
|
+
def compute(self, img: Any, idx: Any, ts: Any) -> Optional[float]:
|
|
40
|
+
v = super().compute(img, idx, ts)
|
|
41
|
+
if self._extra_s > 0:
|
|
42
|
+
time.sleep(self._extra_s)
|
|
43
|
+
return v
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def run(size: int, fps: float, seconds: float, extra_compute_ms: float) -> dict:
|
|
47
|
+
cam = _FakeCamera(fps=fps)
|
|
48
|
+
proc = _BenchMean(name="bench", camera=cam, extra_compute_ms=extra_compute_ms)
|
|
49
|
+
proc.attach(cam)
|
|
50
|
+
|
|
51
|
+
period = 1.0 / fps if fps > 0 else 0.0
|
|
52
|
+
n_target = int(seconds * fps)
|
|
53
|
+
img_buf = np.random.default_rng(0).integers(
|
|
54
|
+
0, 255, size=(size, size), dtype=np.uint16
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
emit_t0 = time.perf_counter()
|
|
58
|
+
next_t = emit_t0
|
|
59
|
+
for i in range(n_target):
|
|
60
|
+
# Mutate a couple of pixels so the mean changes each frame.
|
|
61
|
+
img_buf[i % size, 0] = (i * 13) & 0xFF
|
|
62
|
+
cam.signals.frame.emit(img_buf, i, time.perf_counter() - emit_t0)
|
|
63
|
+
if period:
|
|
64
|
+
next_t += period
|
|
65
|
+
sleep_for = next_t - time.perf_counter()
|
|
66
|
+
if sleep_for > 0:
|
|
67
|
+
time.sleep(sleep_for)
|
|
68
|
+
emit_elapsed = time.perf_counter() - emit_t0
|
|
69
|
+
|
|
70
|
+
# Let the worker drain the last frame.
|
|
71
|
+
time.sleep(max(0.1, (proc.compute_ms_ewma * 3) / 1000.0))
|
|
72
|
+
proc.detach()
|
|
73
|
+
|
|
74
|
+
s = proc.status()
|
|
75
|
+
s["emit_elapsed_s"] = round(emit_elapsed, 3)
|
|
76
|
+
s["target_fps"] = fps
|
|
77
|
+
s["actual_emit_fps"] = round(n_target / emit_elapsed, 1) if emit_elapsed else 0.0
|
|
78
|
+
s["frame_size"] = f"{size}x{size}"
|
|
79
|
+
s["extra_compute_ms"] = extra_compute_ms
|
|
80
|
+
return s
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def main() -> None:
|
|
84
|
+
p = argparse.ArgumentParser()
|
|
85
|
+
p.add_argument("--size", type=int, default=512, help="square frame edge (px)")
|
|
86
|
+
p.add_argument("--fps", type=float, default=60.0, help="target emission rate")
|
|
87
|
+
p.add_argument("--seconds", type=float, default=3.0, help="run duration")
|
|
88
|
+
p.add_argument(
|
|
89
|
+
"--extra-compute-ms",
|
|
90
|
+
type=float,
|
|
91
|
+
default=0.0,
|
|
92
|
+
help="extra artificial compute load per frame (ms)",
|
|
93
|
+
)
|
|
94
|
+
args = p.parse_args()
|
|
95
|
+
|
|
96
|
+
s = run(args.size, args.fps, args.seconds, args.extra_compute_ms)
|
|
97
|
+
width = max(len(k) for k in s)
|
|
98
|
+
for k, v in s.items():
|
|
99
|
+
print(f" {k:<{width}} : {v}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
main()
|