imswitchclient 0.1.2__tar.gz → 0.1.4__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.
- imswitchclient-0.1.4/PKG-INFO +189 -0
- imswitchclient-0.1.4/README.md +150 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient/ImSwitchClient.py +10 -2
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient/__init__.py +1 -1
- imswitchclient-0.1.4/imswitchclient/histoscanManager.py +132 -0
- imswitchclient-0.1.4/imswitchclient/objectiveController.py +45 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient/positionersManager.py +40 -2
- imswitchclient-0.1.4/imswitchclient/recordingManager.py +106 -0
- imswitchclient-0.1.4/imswitchclient/socketClient.py +46 -0
- imswitchclient-0.1.4/imswitchclient.egg-info/PKG-INFO +189 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient.egg-info/SOURCES.txt +4 -11
- imswitchclient-0.1.4/imswitchclient.egg-info/requires.txt +6 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/setup.cfg +3 -3
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/setup.py +4 -4
- imswitchclient-0.1.2/AUTHORS.rst +0 -13
- imswitchclient-0.1.2/PKG-INFO +0 -102
- imswitchclient-0.1.2/README.md +0 -80
- imswitchclient-0.1.2/docs/Makefile +0 -20
- imswitchclient-0.1.2/docs/authors.rst +0 -1
- imswitchclient-0.1.2/docs/conf.py +0 -162
- imswitchclient-0.1.2/docs/contributing.rst +0 -1
- imswitchclient-0.1.2/docs/history.rst +0 -1
- imswitchclient-0.1.2/docs/index.rst +0 -20
- imswitchclient-0.1.2/docs/installation.rst +0 -51
- imswitchclient-0.1.2/docs/make.bat +0 -36
- imswitchclient-0.1.2/docs/readme.rst +0 -1
- imswitchclient-0.1.2/docs/usage.rst +0 -7
- imswitchclient-0.1.2/imswitchclient/recordingManager.py +0 -28
- imswitchclient-0.1.2/imswitchclient.egg-info/PKG-INFO +0 -102
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/CONTRIBUTING.rst +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/HISTORY.rst +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/LICENSE +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/MANIFEST.in +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient/client.py +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient/lasersManager.py +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient.egg-info/dependency_links.txt +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient.egg-info/not-zip-safe +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/imswitchclient.egg-info/top_level.txt +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/tests/__init__.py +0 -0
- {imswitchclient-0.1.2 → imswitchclient-0.1.4}/tests/test_imswitchclient.py +0 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: imswitchclient
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: This is a package that connects ImSwitch's REST API to the rest of the world (e.g. jupyter lab)
|
|
5
|
+
Home-page: https://github.com/openuc2/imswitchclient
|
|
6
|
+
Author: Benedict Diederich
|
|
7
|
+
Author-email: benedictdied@gmail.com
|
|
8
|
+
License: MIT license
|
|
9
|
+
Keywords: imswitchclient
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests
|
|
22
|
+
Requires-Dist: Pillow
|
|
23
|
+
Requires-Dist: numpy
|
|
24
|
+
Requires-Dist: matplotlib
|
|
25
|
+
Requires-Dist: opencv-python
|
|
26
|
+
Requires-Dist: python-socketio==5.12.1
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: description-content-type
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: keywords
|
|
34
|
+
Dynamic: license
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
39
|
+
|
|
40
|
+
# ImSwitchClient Documentation
|
|
41
|
+
|
|
42
|
+
## Introduction
|
|
43
|
+
|
|
44
|
+
`ImSwitchClient` is a Python wrapper designed for interacting with the ImSwitch REST API, enabling remote control over ImSwitch functionalities, such as stage positioning, laser control, and image acquisition. This client simplifies API interactions and allows seamless integration into Python scripts and Jupyter Notebooks.
|
|
45
|
+
|
|
46
|
+
[](https://pypi.python.org/pypi/imswitchclient)
|
|
47
|
+
|
|
48
|
+
## Try on GOOGLE COLAB:
|
|
49
|
+
|
|
50
|
+
Hit this link and test:
|
|
51
|
+
|
|
52
|
+
<a target="_blank" href="https://colab.research.google.com/drive/1W3Jcw4gFn0jtQXa3_2aCtJYJglMNGkXr?usp=sharing">
|
|
53
|
+
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/>
|
|
54
|
+
</a>
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
<a target="_blank" href="https://colab.research.google.com/github/openUC2/imswitchclient/blob/main/examples/StageCalibration.ipynb">
|
|
58
|
+
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/>
|
|
59
|
+
</a>
|
|
60
|
+
|
|
61
|
+
## Features
|
|
62
|
+
|
|
63
|
+
- **Remote Control**: Interface with ImSwitch through REST API endpoints.
|
|
64
|
+
- **Comprehensive API Access**: Easily control positioners, lasers, detectors, and imaging settings.
|
|
65
|
+
- **Interactive API Exploration**: Utilize the FastAPI Swagger UI at `http://localhost:8000/docs`.
|
|
66
|
+
- **Modular Design**: Includes managers for lasers, positioners, image acquisition, and more.
|
|
67
|
+
- **Open Source**: Inspired by OpenFlexure Client, freely available under the MIT license.
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
You can install `ImSwitchClient` via pip:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install imswitchclient
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Getting Started
|
|
78
|
+
|
|
79
|
+
### Initializing the Client
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import imswitchclient.ImSwitchClient as imc
|
|
83
|
+
|
|
84
|
+
# Initialize the client
|
|
85
|
+
client = imc.ImSwitchClient(host="0.0.0.0", isHttps=True, port=8001)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Example: Moving a Stage and Acquiring an Image
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
import numpy as np
|
|
92
|
+
import matplotlib.pyplot as plt
|
|
93
|
+
import time
|
|
94
|
+
|
|
95
|
+
# Retrieve positioner names
|
|
96
|
+
positioner_names = client.positionersManager.getAllDeviceNames()
|
|
97
|
+
positioner_name = positioner_names[0]
|
|
98
|
+
|
|
99
|
+
# Get current position
|
|
100
|
+
current_positions = client.positionersManager.getPositionerPositions()[positioner_name]
|
|
101
|
+
initial_position = (current_positions["X"], current_positions["Y"])
|
|
102
|
+
|
|
103
|
+
# Turn on illumination
|
|
104
|
+
laser_name = client.lasersManager.getLaserNames()[0]
|
|
105
|
+
client.lasersManager.setLaserActive(laser_name, True)
|
|
106
|
+
client.lasersManager.setLaserValue(laser_name, 512)
|
|
107
|
+
|
|
108
|
+
# Move the stage and capture an image
|
|
109
|
+
def capture_image_at_position(x, y):
|
|
110
|
+
client.positionersManager.movePositioner(positioner_name, "X", x, is_absolute=True, is_blocking=True)
|
|
111
|
+
client.positionersManager.movePositioner(positioner_name, "Y", y, is_absolute=True, is_blocking=True)
|
|
112
|
+
last_frame = client.recordingManager.snapNumpyToFastAPI()
|
|
113
|
+
plt.imshow(last_frame)
|
|
114
|
+
plt.show()
|
|
115
|
+
|
|
116
|
+
# Example scanning
|
|
117
|
+
for ix in range(5):
|
|
118
|
+
for iy in range(5):
|
|
119
|
+
new_x = initial_position[0] + ix * 50
|
|
120
|
+
new_y = initial_position[1] + iy * 50
|
|
121
|
+
capture_image_at_position(new_x, new_y)
|
|
122
|
+
|
|
123
|
+
# Return stage to initial position
|
|
124
|
+
client.positionersManager.movePositioner(positioner_name, "X", initial_position[0], is_absolute=True, is_blocking=True)
|
|
125
|
+
client.positionersManager.movePositioner(positioner_name, "Y", initial_position[1], is_absolute=True, is_blocking=True)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Laser Control Example
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
laser_name = client.lasersManager.getLaserNames()[0]
|
|
132
|
+
client.lasersManager.setLaserActive(laser_name, True)
|
|
133
|
+
client.lasersManager.setLaserValue(laser_name, 800)
|
|
134
|
+
|
|
135
|
+
# Verify laser status
|
|
136
|
+
print(client.lasersManager.getLaserNames())
|
|
137
|
+
client.lasersManager.setLaserActive(laser_name, False)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Recording an Image
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
# Take a snapshot
|
|
144
|
+
image = client.recordingManager.snapNumpyToFastAPI()
|
|
145
|
+
plt.imshow(image)
|
|
146
|
+
plt.show()
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Setting Live View
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
client.viewManager.setLiveViewActive(True)
|
|
153
|
+
client.viewManager.setLiveViewCrosshairVisible(True)
|
|
154
|
+
client.viewManager.setLiveViewGridVisible(False)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## API Overview
|
|
158
|
+
|
|
159
|
+
The ImSwitch API provides access to various components:
|
|
160
|
+
|
|
161
|
+
### Positioners Manager
|
|
162
|
+
- `getAllDeviceNames()` - Get all available positioners.
|
|
163
|
+
- `getPositionerPositions()` - Get current position.
|
|
164
|
+
- `movePositioner(name, axis, value, is_absolute, is_blocking)` - Move the stage.
|
|
165
|
+
- `homeAxis(name, axis, is_blocking)` - Home the positioner.
|
|
166
|
+
|
|
167
|
+
### Lasers Manager
|
|
168
|
+
- `getLaserNames()` - Get available lasers.
|
|
169
|
+
- `setLaserActive(name, status)` - Turn laser on/off.
|
|
170
|
+
- `setLaserValue(name, value)` - Set laser intensity.
|
|
171
|
+
|
|
172
|
+
### Recording Manager
|
|
173
|
+
- `snapNumpyToFastAPI()` - Capture an image.
|
|
174
|
+
- `startRecording()` - Begin recording.
|
|
175
|
+
- `stopRecording()` - Stop recording.
|
|
176
|
+
|
|
177
|
+
### View Manager
|
|
178
|
+
- `setLiveViewActive(status)` - Enable live view.
|
|
179
|
+
- `setLiveViewCrosshairVisible(status)` - Show/hide crosshair.
|
|
180
|
+
- `setLiveViewGridVisible(status)` - Show/hide grid.
|
|
181
|
+
|
|
182
|
+
## Contributing
|
|
183
|
+
|
|
184
|
+
Contributions are welcome! Visit the GitHub repository for details: [https://github.com/openUC2/imswitchclient](https://github.com/openUC2/imswitchclient)
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
This project is licensed under the MIT License.
|
|
189
|
+
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# ImSwitchClient Documentation
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
`ImSwitchClient` is a Python wrapper designed for interacting with the ImSwitch REST API, enabling remote control over ImSwitch functionalities, such as stage positioning, laser control, and image acquisition. This client simplifies API interactions and allows seamless integration into Python scripts and Jupyter Notebooks.
|
|
6
|
+
|
|
7
|
+
[](https://pypi.python.org/pypi/imswitchclient)
|
|
8
|
+
|
|
9
|
+
## Try on GOOGLE COLAB:
|
|
10
|
+
|
|
11
|
+
Hit this link and test:
|
|
12
|
+
|
|
13
|
+
<a target="_blank" href="https://colab.research.google.com/drive/1W3Jcw4gFn0jtQXa3_2aCtJYJglMNGkXr?usp=sharing">
|
|
14
|
+
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/>
|
|
15
|
+
</a>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<a target="_blank" href="https://colab.research.google.com/github/openUC2/imswitchclient/blob/main/examples/StageCalibration.ipynb">
|
|
19
|
+
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/>
|
|
20
|
+
</a>
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Remote Control**: Interface with ImSwitch through REST API endpoints.
|
|
25
|
+
- **Comprehensive API Access**: Easily control positioners, lasers, detectors, and imaging settings.
|
|
26
|
+
- **Interactive API Exploration**: Utilize the FastAPI Swagger UI at `http://localhost:8000/docs`.
|
|
27
|
+
- **Modular Design**: Includes managers for lasers, positioners, image acquisition, and more.
|
|
28
|
+
- **Open Source**: Inspired by OpenFlexure Client, freely available under the MIT license.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
You can install `ImSwitchClient` via pip:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install imswitchclient
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Getting Started
|
|
39
|
+
|
|
40
|
+
### Initializing the Client
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import imswitchclient.ImSwitchClient as imc
|
|
44
|
+
|
|
45
|
+
# Initialize the client
|
|
46
|
+
client = imc.ImSwitchClient(host="0.0.0.0", isHttps=True, port=8001)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Example: Moving a Stage and Acquiring an Image
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import numpy as np
|
|
53
|
+
import matplotlib.pyplot as plt
|
|
54
|
+
import time
|
|
55
|
+
|
|
56
|
+
# Retrieve positioner names
|
|
57
|
+
positioner_names = client.positionersManager.getAllDeviceNames()
|
|
58
|
+
positioner_name = positioner_names[0]
|
|
59
|
+
|
|
60
|
+
# Get current position
|
|
61
|
+
current_positions = client.positionersManager.getPositionerPositions()[positioner_name]
|
|
62
|
+
initial_position = (current_positions["X"], current_positions["Y"])
|
|
63
|
+
|
|
64
|
+
# Turn on illumination
|
|
65
|
+
laser_name = client.lasersManager.getLaserNames()[0]
|
|
66
|
+
client.lasersManager.setLaserActive(laser_name, True)
|
|
67
|
+
client.lasersManager.setLaserValue(laser_name, 512)
|
|
68
|
+
|
|
69
|
+
# Move the stage and capture an image
|
|
70
|
+
def capture_image_at_position(x, y):
|
|
71
|
+
client.positionersManager.movePositioner(positioner_name, "X", x, is_absolute=True, is_blocking=True)
|
|
72
|
+
client.positionersManager.movePositioner(positioner_name, "Y", y, is_absolute=True, is_blocking=True)
|
|
73
|
+
last_frame = client.recordingManager.snapNumpyToFastAPI()
|
|
74
|
+
plt.imshow(last_frame)
|
|
75
|
+
plt.show()
|
|
76
|
+
|
|
77
|
+
# Example scanning
|
|
78
|
+
for ix in range(5):
|
|
79
|
+
for iy in range(5):
|
|
80
|
+
new_x = initial_position[0] + ix * 50
|
|
81
|
+
new_y = initial_position[1] + iy * 50
|
|
82
|
+
capture_image_at_position(new_x, new_y)
|
|
83
|
+
|
|
84
|
+
# Return stage to initial position
|
|
85
|
+
client.positionersManager.movePositioner(positioner_name, "X", initial_position[0], is_absolute=True, is_blocking=True)
|
|
86
|
+
client.positionersManager.movePositioner(positioner_name, "Y", initial_position[1], is_absolute=True, is_blocking=True)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Laser Control Example
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
laser_name = client.lasersManager.getLaserNames()[0]
|
|
93
|
+
client.lasersManager.setLaserActive(laser_name, True)
|
|
94
|
+
client.lasersManager.setLaserValue(laser_name, 800)
|
|
95
|
+
|
|
96
|
+
# Verify laser status
|
|
97
|
+
print(client.lasersManager.getLaserNames())
|
|
98
|
+
client.lasersManager.setLaserActive(laser_name, False)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Recording an Image
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# Take a snapshot
|
|
105
|
+
image = client.recordingManager.snapNumpyToFastAPI()
|
|
106
|
+
plt.imshow(image)
|
|
107
|
+
plt.show()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Setting Live View
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
client.viewManager.setLiveViewActive(True)
|
|
114
|
+
client.viewManager.setLiveViewCrosshairVisible(True)
|
|
115
|
+
client.viewManager.setLiveViewGridVisible(False)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## API Overview
|
|
119
|
+
|
|
120
|
+
The ImSwitch API provides access to various components:
|
|
121
|
+
|
|
122
|
+
### Positioners Manager
|
|
123
|
+
- `getAllDeviceNames()` - Get all available positioners.
|
|
124
|
+
- `getPositionerPositions()` - Get current position.
|
|
125
|
+
- `movePositioner(name, axis, value, is_absolute, is_blocking)` - Move the stage.
|
|
126
|
+
- `homeAxis(name, axis, is_blocking)` - Home the positioner.
|
|
127
|
+
|
|
128
|
+
### Lasers Manager
|
|
129
|
+
- `getLaserNames()` - Get available lasers.
|
|
130
|
+
- `setLaserActive(name, status)` - Turn laser on/off.
|
|
131
|
+
- `setLaserValue(name, value)` - Set laser intensity.
|
|
132
|
+
|
|
133
|
+
### Recording Manager
|
|
134
|
+
- `snapNumpyToFastAPI()` - Capture an image.
|
|
135
|
+
- `startRecording()` - Begin recording.
|
|
136
|
+
- `stopRecording()` - Stop recording.
|
|
137
|
+
|
|
138
|
+
### View Manager
|
|
139
|
+
- `setLiveViewActive(status)` - Enable live view.
|
|
140
|
+
- `setLiveViewCrosshairVisible(status)` - Show/hide crosshair.
|
|
141
|
+
- `setLiveViewGridVisible(status)` - Show/hide grid.
|
|
142
|
+
|
|
143
|
+
## Contributing
|
|
144
|
+
|
|
145
|
+
Contributions are welcome! Visit the GitHub repository for details: [https://github.com/openUC2/imswitchclient](https://github.com/openUC2/imswitchclient)
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
This project is licensed under the MIT License.
|
|
150
|
+
|
|
@@ -10,10 +10,12 @@ import os
|
|
|
10
10
|
from .positionersManager import positionersManager
|
|
11
11
|
from .recordingManager import recordingManager
|
|
12
12
|
from .lasersManager import lasersManager
|
|
13
|
-
|
|
13
|
+
from .histoscanManager import histoscanManager
|
|
14
|
+
from .objectiveController import objectiveController
|
|
15
|
+
from .socketClient import socketClient
|
|
14
16
|
|
|
15
17
|
class ImSwitchClient(object):
|
|
16
|
-
def __init__(self, host="0.0.0.0", isHttps=True, port=8001):
|
|
18
|
+
def __init__(self, host="0.0.0.0", isHttps=True, port=8001, socket_port=8002):
|
|
17
19
|
self.host = host
|
|
18
20
|
self.port = port
|
|
19
21
|
self.isHttps = isHttps
|
|
@@ -25,6 +27,12 @@ class ImSwitchClient(object):
|
|
|
25
27
|
self.positionersManager = positionersManager(self)
|
|
26
28
|
self.recordingManager = recordingManager(self)
|
|
27
29
|
self.lasersManager = lasersManager(self)
|
|
30
|
+
self.histoscanManager = histoscanManager(self)
|
|
31
|
+
self.objectiveController = objectiveController(self)
|
|
32
|
+
|
|
33
|
+
# initialize Socket.IO client
|
|
34
|
+
self.socketClient = socketClient(host=self.host, port=socket_port, isHttps=self.isHttps)
|
|
35
|
+
|
|
28
36
|
|
|
29
37
|
@property
|
|
30
38
|
def base_uri(self):
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
from PIL import Image
|
|
2
|
+
import numpy as np
|
|
3
|
+
import io
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
class histoscanManager(object):
|
|
7
|
+
|
|
8
|
+
'''
|
|
9
|
+
http://localhost:8001/HistoScanController/startHistoScanTileBasedByParameters?numberTilesX=2&numberTilesY=2&stepSizeX=100&stepSizeY=100&nTimes=1&tPeriod=1&initPosX=0&initPosY=0
|
|
10
|
+
http://localhost:8001/HistoScanController/startStageMapping
|
|
11
|
+
http://localhost:8001/HistoScanController/stopHistoScan
|
|
12
|
+
'''
|
|
13
|
+
|
|
14
|
+
def __init__(self, parent):
|
|
15
|
+
self.parent = parent
|
|
16
|
+
|
|
17
|
+
def stopHistoScan(self):
|
|
18
|
+
url = f"{self.parent.base_uri}/HistoScanController/stopHistoScan"
|
|
19
|
+
headers = {'accept': 'application/json'}
|
|
20
|
+
response = self.parent.get_json(url, headers=headers)
|
|
21
|
+
return response
|
|
22
|
+
|
|
23
|
+
def startStageScanningPositionlistbased(self, positionList:list, nTimes:int=1, tPeriod:int=1, illuSource:str=None):
|
|
24
|
+
url = f"{self.parent.base_uri}/HistoScanController/startStageScanningPositionlistbased"
|
|
25
|
+
|
|
26
|
+
payload = {
|
|
27
|
+
"positionList": str(positionList),
|
|
28
|
+
"nTimes": nTimes,
|
|
29
|
+
"tPeriod": tPeriod,
|
|
30
|
+
"illuSource": illuSource
|
|
31
|
+
}
|
|
32
|
+
if nTimes < 1:
|
|
33
|
+
raise ValueError("nTimes must be greater than 0")
|
|
34
|
+
response = self.parent.get_json(url, payload=payload)
|
|
35
|
+
return response
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def startStageScanningPositionlistbased(self, positionList:str, nTimes:int=1, tPeriod:int=1, illuSource:str=None):
|
|
39
|
+
'''
|
|
40
|
+
https://localhost:8001/HistoScanController/startStageScanningPositionlistbased?positionList=dadf&nTimes=1&tPeriod=0
|
|
41
|
+
|
|
42
|
+
positionList: list of tuples with X/Y positions (e.g. "[(10, 10, 100), (100, 100, 100)]")
|
|
43
|
+
nTimes: number of times to repeat the scan
|
|
44
|
+
tPeriod: time between scans
|
|
45
|
+
'''
|
|
46
|
+
|
|
47
|
+
url = f"{self.parent.base_uri}/HistoScanController/startStageScanningPositionlistbased"
|
|
48
|
+
payload = {
|
|
49
|
+
"positionList": positionList,
|
|
50
|
+
"nTimes": nTimes,
|
|
51
|
+
"tPeriod": tPeriod,
|
|
52
|
+
"illuSource": illuSource
|
|
53
|
+
}
|
|
54
|
+
if nTimes < 1:
|
|
55
|
+
raise ValueError("nTimes must be greater than 0")
|
|
56
|
+
response = self.parent.get_json(url, payload=payload)
|
|
57
|
+
return response
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def startHistoScanTileBasedByParameters(self, numberTilesX, numberTilesY, stepSizeX, stepSizeY, initPosX, initPosY, nTimes=1, tPeriod=1):
|
|
61
|
+
url = f"{self.parent.base_uri}/HistoScanController/startHistoScanTileBasedByParameters"
|
|
62
|
+
payload = {
|
|
63
|
+
"numberTilesX": numberTilesX,
|
|
64
|
+
"numberTilesY": numberTilesY,
|
|
65
|
+
"stepSizeX": stepSizeX,
|
|
66
|
+
"stepSizeY": stepSizeY,
|
|
67
|
+
"nTimes": nTimes,
|
|
68
|
+
"tPeriod": tPeriod,
|
|
69
|
+
"initPosX": initPosX,
|
|
70
|
+
"initPosY": initPosY
|
|
71
|
+
}
|
|
72
|
+
if nTimes < 1:
|
|
73
|
+
raise ValueError("nTimes must be greater than 0")
|
|
74
|
+
response = self.parent.get_json(url, payload=payload)
|
|
75
|
+
return response
|
|
76
|
+
|
|
77
|
+
def startStageMapping(self):
|
|
78
|
+
url = f"{self.parent.base_uri}/HistoScanController/startStageMapping"
|
|
79
|
+
payload = {
|
|
80
|
+
}
|
|
81
|
+
response = self.parent.get_json(url, payload=payload)
|
|
82
|
+
return response
|
|
83
|
+
|
|
84
|
+
def getStatusScanRunning(self):
|
|
85
|
+
url = f"{self.parent.base_uri}/HistoScanController/getStatusScanRunning"
|
|
86
|
+
payload = {
|
|
87
|
+
}
|
|
88
|
+
response = self.parent.get_json(url, payload=payload)
|
|
89
|
+
return response
|
|
90
|
+
|
|
91
|
+
def getLastStitchedImage(self):
|
|
92
|
+
'''
|
|
93
|
+
https://localhost:8001/HistoScanController/
|
|
94
|
+
Retrieve numpy image based on
|
|
95
|
+
return Response(im_bytes, headers=headers, media_type='image/png')
|
|
96
|
+
'''
|
|
97
|
+
url = f"{self.parent.base_uri}/HistoScanController/getLastStitchedImage"
|
|
98
|
+
headers = {'accept': 'application/json'}
|
|
99
|
+
response = self.parent.get_json(url, headers=headers)
|
|
100
|
+
content_type = response.headers.get('content-type')
|
|
101
|
+
if content_type == 'image/png':
|
|
102
|
+
image_data = response.content
|
|
103
|
+
image = Image.open(io.BytesIO(image_data))
|
|
104
|
+
return np.array(image)
|
|
105
|
+
else:
|
|
106
|
+
raise ValueError("Unexpected response content-type. Expected 'image/png'.")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def startStageScanning(self, minPosX:float=None, maxPosX:float=None, minPosY:float=None, maxPosY:float=None,
|
|
110
|
+
overlap:float=None, nTimes:int=1, tPeriod:int=0, positionList:list=None,
|
|
111
|
+
isStitchAshlar:bool=False, isStitchAshlarFlipX:bool=False, isStitchAshlarFlipY:bool=False,
|
|
112
|
+
resizeFactor=0.25):
|
|
113
|
+
'''
|
|
114
|
+
generic stage scan, rather low-level
|
|
115
|
+
'''
|
|
116
|
+
url = f"{self.parent.base_uri}/HistoScanController/startStageScanning"
|
|
117
|
+
payload = {
|
|
118
|
+
"minPosX": minPosX,
|
|
119
|
+
"maxPosX": maxPosX,
|
|
120
|
+
"minPosY": minPosY,
|
|
121
|
+
"maxPosY": maxPosY,
|
|
122
|
+
"overlap": overlap,
|
|
123
|
+
"nTimes": nTimes,
|
|
124
|
+
"tPeriod": tPeriod,
|
|
125
|
+
"positionList": json.dumps(positionList),
|
|
126
|
+
"isStitchAshlar": isStitchAshlar,
|
|
127
|
+
"isStitchAshlarFlipX": isStitchAshlarFlipX,
|
|
128
|
+
"isStitchAshlarFlipY": isStitchAshlarFlipY,
|
|
129
|
+
"resizeFactor": resizeFactor
|
|
130
|
+
}
|
|
131
|
+
response = self.parent.get_json(url, payload=payload)
|
|
132
|
+
return response
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class objectiveController(object):
|
|
2
|
+
|
|
3
|
+
def __init__(self, parent):
|
|
4
|
+
self.parent = parent
|
|
5
|
+
|
|
6
|
+
def calibrateObjective(self, homeDirection=None, homePolarity=None):
|
|
7
|
+
url = f"{self.parent.base_uri}/ObjectiveController/calibrateObjective"
|
|
8
|
+
params = {}
|
|
9
|
+
if homeDirection is not None:
|
|
10
|
+
params['homeDirection'] = homeDirection
|
|
11
|
+
if homePolarity is not None:
|
|
12
|
+
params['homePolarity'] = homePolarity
|
|
13
|
+
response = self.parent.get_json(url, payload=params)
|
|
14
|
+
return response
|
|
15
|
+
|
|
16
|
+
def getCurrentObjective(self):
|
|
17
|
+
url = f"{self.parent.base_uri}/ObjectiveController/getCurrentObjective"
|
|
18
|
+
response = self.parent.get_json(url)
|
|
19
|
+
return response
|
|
20
|
+
|
|
21
|
+
def getStatus(self):
|
|
22
|
+
url = f"{self.parent.base_uri}/ObjectiveController/getstatus"
|
|
23
|
+
response = self.parent.get_json(url)
|
|
24
|
+
return response
|
|
25
|
+
|
|
26
|
+
def moveToObjective(self, slot):
|
|
27
|
+
url = f"{self.parent.base_uri}/ObjectiveController/moveToObjective"
|
|
28
|
+
payload = {"slot": slot}
|
|
29
|
+
response = self.parent.get_json(url, payload=payload)
|
|
30
|
+
return response
|
|
31
|
+
|
|
32
|
+
def setPositions(self, x1=None, x2=None, z1=None, z2=None, isBlocking=False):
|
|
33
|
+
url = f"{self.parent.base_uri}/ObjectiveController/setPositions"
|
|
34
|
+
payload = {}
|
|
35
|
+
if x1 is not None:
|
|
36
|
+
payload["x1"] = x1
|
|
37
|
+
if x2 is not None:
|
|
38
|
+
payload["x2"] = x2
|
|
39
|
+
if z1 is not None:
|
|
40
|
+
payload["z1"] = z1
|
|
41
|
+
if z2 is not None:
|
|
42
|
+
payload["z2"] = z2
|
|
43
|
+
payload["isBlocking"] = isBlocking
|
|
44
|
+
response = self.parent.get_json(url, payload=payload)
|
|
45
|
+
return response
|
|
@@ -3,6 +3,7 @@ class positionersManager(object):
|
|
|
3
3
|
|
|
4
4
|
def __init__(self, parent):
|
|
5
5
|
self.parent = parent
|
|
6
|
+
self.allStageNames = self.getAllDeviceNames()
|
|
6
7
|
|
|
7
8
|
def getAllDeviceNames(self):
|
|
8
9
|
url = f"{self.parent.base_uri}/PositionerController/getPositionerNames"
|
|
@@ -10,10 +11,26 @@ class positionersManager(object):
|
|
|
10
11
|
|
|
11
12
|
response = self.parent.get_json(url, headers=headers)
|
|
12
13
|
return response
|
|
13
|
-
|
|
14
|
+
|
|
15
|
+
def stop(self, positioner_name, axis):
|
|
16
|
+
if positioner_name is None:
|
|
17
|
+
positioner_name = self.allStageNames[0]
|
|
18
|
+
|
|
19
|
+
url = f"{self.parent.base_uri}/PositionerController/stop"
|
|
20
|
+
payload = {
|
|
21
|
+
'positionerName': positioner_name,
|
|
22
|
+
'axis': axis
|
|
23
|
+
}
|
|
24
|
+
response = self.parent.get_json(url, payload=payload)
|
|
25
|
+
return response
|
|
26
|
+
|
|
14
27
|
def movePositionerForever(self, speed=(0, 0, 0, 0), is_stop=False):
|
|
28
|
+
if positioner_name is None:
|
|
29
|
+
positioner_name = self.allStageNames[0]
|
|
30
|
+
|
|
15
31
|
url = f"{self.parent.base_uri}/PositionerController/movePositionerForever"
|
|
16
32
|
payload = {
|
|
33
|
+
'positionerName': positioner_name,
|
|
17
34
|
'speed': speed,
|
|
18
35
|
'isStop': is_stop
|
|
19
36
|
}
|
|
@@ -21,6 +38,9 @@ class positionersManager(object):
|
|
|
21
38
|
return response
|
|
22
39
|
|
|
23
40
|
def setPositionerSpeed(self, positioner_name, axis, speed):
|
|
41
|
+
if positioner_name is None:
|
|
42
|
+
positioner_name = self.allStageNames[0]
|
|
43
|
+
|
|
24
44
|
url = f"{self.parent.base_uri}/PositionerController/setPositionerSpeed"
|
|
25
45
|
payload = {
|
|
26
46
|
'positionerName': positioner_name,
|
|
@@ -31,6 +51,9 @@ class positionersManager(object):
|
|
|
31
51
|
return response
|
|
32
52
|
|
|
33
53
|
def movePositioner(self, positioner_name, axis, dist, is_absolute=True, is_blocking=True, speed=10000):
|
|
54
|
+
if positioner_name is None:
|
|
55
|
+
positioner_name = self.allStageNames[0]
|
|
56
|
+
|
|
34
57
|
url = f"{self.parent.base_uri}/PositionerController/movePositioner"
|
|
35
58
|
payload = {
|
|
36
59
|
'positionerName': positioner_name,
|
|
@@ -45,9 +68,24 @@ class positionersManager(object):
|
|
|
45
68
|
response = self.parent.get_json(url, payload=payload)
|
|
46
69
|
return response
|
|
47
70
|
|
|
48
|
-
def getPositionerPositions(self):
|
|
71
|
+
def getPositionerPositions(self, id=None):
|
|
49
72
|
url = f"{self.parent.base_uri}/PositionerController/getPositionerPositions"
|
|
50
73
|
payload = {
|
|
51
74
|
}
|
|
52
75
|
response = self.parent.get_json(url, payload=payload)
|
|
76
|
+
if type(id) == int:
|
|
77
|
+
return response[id]
|
|
78
|
+
return response
|
|
79
|
+
|
|
80
|
+
def homeAxis(self, positioner_name, axis, is_blocking=False):
|
|
81
|
+
url = f"{self.parent.base_uri}/PositionerController/homeAxis"
|
|
82
|
+
if positioner_name is None:
|
|
83
|
+
positioner_name = self.allStageNames[0]
|
|
84
|
+
|
|
85
|
+
payload = {
|
|
86
|
+
'positionerName': positioner_name,
|
|
87
|
+
'axis': axis,
|
|
88
|
+
'isBlocking': is_blocking
|
|
89
|
+
}
|
|
90
|
+
response = self.parent.get_json(url, payload=payload)
|
|
53
91
|
return response
|