Skip to content

Commit 5b63ce8

Browse files
author
User
committed
v0.2.6: Fix axis preservation, enhance API docs, and add plugin tooltips
- Fixed critical axis order bug in revert_to_original_axis_order() - register_image_from_file now correctly preserves input axis format (TZCYX→TZCYX, TZYX→TZYX, etc.) - Updated type annotations: ref_channel supports int, str, list, and tuple - Added comprehensive multi-channel reference examples in API_REFERENCE.md - Added tooltips to all plugin buttons and controls explaining functionality - Added API-only installation instructions [api-only] to API_REFERENCE.md - Updated test expectations to match new axis preservation behavior - Removed obsolete test files (test_axis_fix.py, test_gpu_detection.py, test_registration.py) - All 43 tests passing
1 parent 1ab3d03 commit 5b63ce8

13 files changed

Lines changed: 344 additions & 2343 deletions

File tree

API_REFERENCE.md

Lines changed: 165 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@
22

33
## Installation
44

5+
### Full Installation (with napari GUI plugin)
6+
57
```bash
68
pip install napari-fast4dreg
79
```
810

11+
### API-Only Installation (lightweight, no GUI dependencies)
12+
13+
```bash
14+
pip install napari-fast4dreg[api-only]
15+
```
16+
17+
Use the API-only installation if you only need programmatic access and want to avoid installing napari and its dependencies.
18+
919
## Three Ways to Use Fast4DReg
1020

1121
### 1. napari GUI (Interactive)
@@ -46,21 +56,42 @@ xy_drift = result['xy_drift']
4656
```python
4757
from napari_fast4dreg import register_image_from_file
4858

59+
# TIFF file (ImageJ format)
4960
result = register_image_from_file(
5061
"my_image.tif",
5162
axis_order="TZCYX", # ImageJ format
5263
ref_channel=1,
5364
output_dir="./results"
5465
)
66+
67+
# NumPy binary file
68+
result = register_image_from_file(
69+
"my_image.npy",
70+
axis_order="CZYX",
71+
ref_channel=0,
72+
output_dir="./results"
73+
)
74+
75+
# Zarr file (chunked)
76+
result = register_image_from_file(
77+
"my_image.zarr",
78+
axis_order="CTZYX",
79+
ref_channel=0,
80+
output_dir="./results"
81+
)
82+
83+
# Output is always same shape as input shape
84+
registered = result['registered_image']
85+
xy_drift = result['xy_drift']
5586
```
5687

5788
## Common Parameters
5889

5990
| Parameter | Type | Default | Description |
6091
|-----------|------|---------|-------------|
6192
| `image` | ndarray/dask | required | Image in specified axis order |
62-
| `axis_order` | str | "CTZYX" | Axis order: CTZYX, TZYX, ZYX, ZCYX, etc. Missing axes auto-added |
63-
| `ref_channel` | int/str | 0 | Reference channel(s): int (e.g., `0`), comma-separated (e.g., `"0,1"`) |
93+
| `axis_order` | str | "CTZYX" | Axis order: CTZYX, TZCYX, TZYX, ZYX, CZYX, CYX, TYX, or YX. Missing axes auto-added |
94+
| `ref_channel` | int/str/list/tuple | 0 | Reference channel(s): int (e.g., `0`), list (e.g., `[0,1,5]`), comma-separated string (e.g., `"0,1,5"`), space-separated (e.g., `"0 1 5"`) |
6495
| `output_dir` | str/Path | "./fast4dreg_output" | Output directory |
6596
| `correct_xy` | bool | True | Apply XY drift correction |
6697
| `correct_z` | bool | True | Apply Z drift correction |
@@ -78,16 +109,37 @@ result = register_image_from_file(
78109
Dictionary containing:
79110
```python
80111
{
81-
'registered_image': np.ndarray, # Registered image (same axis order as input)
82-
'xy_drift': np.ndarray, # XY drift values
83-
'z_drift': np.ndarray, # Z drift values
112+
'registered_image': dask.array.Array, # Registered image (dask array, lazy-loaded)
113+
# For register_image: same axis order as input
114+
# For register_image_from_file: always CTZYX
115+
'xy_drift': np.ndarray, # XY drift values (T, 2)
116+
'z_drift': np.ndarray, # Z drift values (T, 2)
84117
'rotation_xy': np.ndarray, # XY rotation angles
85118
'rotation_zx': np.ndarray, # ZX rotation angles
86119
'rotation_zy': np.ndarray, # ZY rotation angles
87120
'output_path': Path # Path to saved Zarr
88121
}
89122
```
90123

124+
### Working with the Registered Image
125+
126+
The `registered_image` is a **dask array**, meaning it's lazy-loaded from Zarr storage:
127+
128+
```python
129+
result = register_image(image, ...}
130+
registered = result['registered_image'] # dask.array, not in RAM
131+
132+
# Convert to numpy if needed (loads into memory, make sure it fits)
133+
registered_np = registered.compute()
134+
135+
# Or work with it directly for out-of-memory processing
136+
mip_projection = registered.max(axis = 2).compute()
137+
138+
# Or save chunks back to disk
139+
import dask.array as da
140+
da.to_zarr(registered, "path/to/output.zarr")
141+
```
142+
91143
## Supported Axis Orders
92144

93145
The `axis_order` parameter accepts flexible axis specifications:
@@ -100,8 +152,8 @@ The `axis_order` parameter accepts flexible axis specifications:
100152
| `CZYX` | (C, Z, Y, X) | 4D, single timepoint |
101153
| `ZYX` | (Z, Y, X) | 3D single timepoint + channel |
102154
| `TYX` | (T, Y, X) | Time series 2D |
103-
| `CYX` | (C, Y, X) | Multi-channel 2D image |
104-
| `YX` | (Y, X) | Single 2D image |
155+
| `CYX` | (C, Y, X) | Multi-channel 2D image (included for pipeline savety) |
156+
| `YX` | (Y, X) | Single 2D image (included for pipeline savety) |
105157

106158
Missing dimensions are automatically inserted as singletons during processing and removed in the output.
107159

@@ -175,16 +227,43 @@ result = register_image(
175227
### Multi-Channel Reference
176228

177229
```python
178-
# Use multiple channels - comma or space-separated
230+
# Multiple ways to specify multiple reference channels:
231+
232+
# Option 1: List of integers
233+
result = register_image(
234+
image,
235+
ref_channel=[0, 3, 5], # List of channel indices
236+
normalize_channels=True,
237+
projection_type='max'
238+
)
239+
240+
# Option 2: Tuple of integers
179241
result = register_image(
180242
image,
181-
ref_channel="0,3,5", # Use channels 0, 3, and 5 (comma-separated)
182-
# OR: ref_channel="0 3 5" # Space-separated also works
243+
ref_channel=(0, 3, 5), # Tuple - same as list
244+
normalize_channels=True,
245+
projection_type='max'
246+
)
247+
248+
# Option 3: Comma-separated string
249+
result = register_image(
250+
image,
251+
ref_channel="0,3,5", # Comma-separated string
252+
normalize_channels=True,
253+
projection_type='max'
254+
)
255+
256+
# Option 4: Space-separated string
257+
result = register_image(
258+
image,
259+
ref_channel="0 3 5", # Space-separated string
183260
normalize_channels=True,
184261
projection_type='max'
185262
)
186263
```
187264

265+
All formats above produce the same result: channels 0, 3, and 5 are summed together for drift detection.
266+
188267
### Integration into Workflow
189268

190269
```python
@@ -216,12 +295,32 @@ print(f"Maximum drift: {max_drift:.2f} pixels")
216295
```python
217296
from napari_fast4dreg import register_image_from_file
218297

298+
# ImageJ format (TZCYX) - Output will be TZCYX
219299
result = register_image_from_file(
220300
"timelapse.tif",
221-
axis_order="TZCYX", # ImageJ: Time, Z, Channel, Y, X
301+
axis_order="TZCYX", # Time, Z, Channel, Y, X (default for TIFF)
222302
ref_channel=1,
223303
output_dir="./results"
224304
)
305+
registered = result['registered_image'] # Shape: (T, Z, C, Y, X)
306+
307+
# Single channel TIFF (TZYX) - Output will be TZYX
308+
result = register_image_from_file(
309+
"timelapse.tif",
310+
axis_order="TZYX", # Time, Z, Y, X
311+
ref_channel=0,
312+
output_dir="./results"
313+
)
314+
registered = result['registered_image'] # Shape: (T, Z, Y, X)
315+
316+
# NumPy array file (.npy)
317+
result = register_image_from_file(
318+
"image_stack.npy",
319+
axis_order="CZYX", # Channels, Z, Y, X
320+
ref_channel="0,1",
321+
output_dir="./results"
322+
)
323+
registered = result['registered_image'] # Shape: (C, Z, Y, X)
225324
```
226325

227326
### Batch Processing
@@ -249,39 +348,75 @@ for tif_file in input_dir.glob("*.tif"):
249348

250349
## Axis Order Formats
251350

252-
Fast4DReg expects **CTZYX** format (Channels, Time, Z, Y, X).
351+
Fast4DReg processes images in **CTZYX** format internally, but input and output formats are flexible.
253352

254-
Common conversions:
255-
- **ImageJ/Fiji** (`TZCYX`): Use `axis_order="TZCYX"` in `register_image_from_file()`
256-
- **Single channel** (`TZYX`): Use `axis_order="TZYX"` - channel dimension is added automatically
257-
- **Already CTZYX**: Use `axis_order="CTZYX"` or pass directly to `register_image()`
353+
### Input/Output Axis Orders
354+
- **register_image()**: Input in format X, output in format X (same as input)
355+
- **register_image_from_file()**: Input in format X, output in format X (same as input file)
356+
357+
### Supported Formats
358+
- `CTZYX` - Standard 5D (Channels, Time, Z, Y, X)
359+
- `TZCYX` - ImageJ/Fiji format (Time, Z, Channels, Y, X) [DEFAULT for register_image_from_file]
360+
- `TZYX` - Single channel time series (Time, Z, Y, X)
361+
- `CZYX` - Multi-channel single timepoint (Channels, Z, Y, X)
362+
- `ZYX` - Single timepoint single channel volume (Z, Y, X)
363+
- `CYX` - Multi-channel 2D image (Channels, Y, X)
364+
- `TYX` - 2D time series (Time, Y, X)
365+
- `YX` - Single 2D image
366+
367+
Missing dimensions (C, T, Z) are automatically inserted as singletons during processing.
368+
369+
### Example: Axis Order Preservation
258370

259-
Manual conversion:
260371
```python
372+
from napari_fast4dreg import register_image, register_image_from_file
261373
import numpy as np
262374

263-
# TZCYX → CTZYX
264-
image_ctzyx = np.moveaxis(image_tzcyx, [0, 1, 2], [1, 2, 0])
375+
# register_image preserves input format
376+
image_tzyx = np.load("data.npy") # Shape: (T, Z, Y, X)
377+
result = register_image(image_tzyx, axis_order="TZYX")
378+
output = result['registered_image'] # Still TZYX: (T, Z, Y, X)
379+
380+
# register_image_from_file preserves file format
381+
# File is TZCYX, output is TZCYX
382+
result = register_image_from_file("data.tif", axis_order="TZCYX")
383+
output = result['registered_image'] # TZCYX: (T, Z, C, Y, X)
265384

266-
# TZYX → CTZYX (add channel dim)
267-
image_ctzyx = image_tzyx[:, np.newaxis, ...]
385+
# Custom format also preserved
386+
result = register_image_from_file("data.npy", axis_order="CZYX")
387+
output = result['registered_image'] # CZYX: (C, Z, Y, X)
268388
```
269389

270390
## Output Files
271391

272392
When registration completes, you'll find:
273-
- `registered.zarr/` - Final registered image (Zarr format)
393+
- `registered.zarr/` - Final registered image (Zarr format, dask-accessible)
394+
- Format matches your input's axis_order
395+
- For TZCYX input: output is TZCYX
396+
- For CZYX input: output is CZYX
397+
- etc.
274398
- `tmp_data_*.zarr/` - Temporary stores (deleted unless `keep_temp_files=True`)
275399

276-
Load the output in napari or Python:
400+
Load and work with the output:
277401
```python
278-
# In napari
279-
viewer.open("./results/registered.zarr")
402+
# From the result dictionary
403+
result = register_image_from_file("data.tif", axis_order="TZCYX")
404+
registered = result['registered_image'] # dask.array in TZCYX format
280405

281-
# In Python
406+
# Or load manually from disk
282407
import dask.array as da
283-
import zarr
284-
registered = da.from_zarr("./results/registered.zarr")
408+
registered = da.from_zarr("./results/registered.zarr") # Format matches input
409+
410+
# Convert to numpy for analysis
411+
registered_np = registered.compute()
412+
413+
# Or process chunks without loading all into RAM
414+
mean = registered.mean().compute()
415+
max_val = registered.max().compute()
416+
417+
# View in napari (napari accepts dask arrays directly)
418+
import napari
419+
viewer = napari.view_image(registered)
285420
```
286421

287422
## Tips
@@ -296,13 +431,13 @@ registered = da.from_zarr("./results/registered.zarr")
296431

297432
## GPU Acceleration (Optional)
298433

299-
Fast4DReg **automatically detects and enables GPU acceleration** when available using [pyclesperanto](https://github.com/clEsperanto/pyclesperanto_prototype) for all transformation operations (translations and rotations).
434+
Fast4DReg **automatically detects and enables GPU acceleration** when available using [pyclesperanto](https://github.com/clEsperanto/pyclesperanto) for all transformation operations (translations and rotations).
300435

301436
### Installation
302437

303438
```bash
304439
# Install pyclesperanto for GPU support
305-
pip install pyclesperanto-prototype
440+
pip install pyclesperanto
306441
```
307442

308443
### Automatic Detection

0 commit comments

Comments
 (0)