micro-reader 0.0.4__tar.gz → 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 (68) hide show
  1. {micro_reader-0.0.4 → micro_reader-0.2.0}/PKG-INFO +86 -40
  2. {micro_reader-0.0.4 → micro_reader-0.2.0}/README.md +82 -38
  3. {micro_reader-0.0.4 → micro_reader-0.2.0}/pyproject.toml +6 -4
  4. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/__init__.py +12 -7
  5. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_base.py +240 -22
  6. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_codecs.py +43 -5
  7. micro_reader-0.2.0/src/micro_reader/_errors.py +63 -0
  8. micro_reader-0.2.0/src/micro_reader/_eubi_guard.py +189 -0
  9. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_fileset.py +6 -1
  10. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_groups.py +11 -6
  11. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_io.py +1 -1
  12. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_metadata.py +20 -0
  13. micro_reader-0.2.0/src/micro_reader/_mosaic.py +80 -0
  14. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_outline.py +9 -7
  15. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_plate.py +48 -3
  16. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_pool.py +1 -1
  17. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_registry.py +69 -23
  18. micro_reader-0.2.0/src/micro_reader/_spatial.py +517 -0
  19. micro_reader-0.2.0/src/micro_reader/_stack.py +83 -0
  20. micro_reader-0.2.0/src/micro_reader/_version.py +2 -0
  21. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/_czi_metadata.py +18 -4
  22. micro_reader-0.2.0/src/micro_reader/backends/_hdf5.py +1021 -0
  23. micro_reader-0.2.0/src/micro_reader/backends/_lif_metadata.py +256 -0
  24. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/_nd2_legacy.py +1 -1
  25. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/_nd2_metadata.py +60 -23
  26. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/_tiff_metadata.py +146 -28
  27. micro_reader-0.2.0/src/micro_reader/backends/_tiff_variants.py +475 -0
  28. micro_reader-0.2.0/src/micro_reader/backends/bdv.py +919 -0
  29. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/companion.py +83 -36
  30. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/cv7000.py +58 -15
  31. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/czi.py +279 -66
  32. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/harmony.py +104 -29
  33. micro_reader-0.2.0/src/micro_reader/backends/hdf5.py +260 -0
  34. micro_reader-0.2.0/src/micro_reader/backends/ics.py +480 -0
  35. micro_reader-0.2.0/src/micro_reader/backends/ilastik.py +157 -0
  36. micro_reader-0.2.0/src/micro_reader/backends/ims.py +363 -0
  37. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/incell.py +3 -3
  38. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/lif.py +60 -20
  39. micro_reader-0.2.0/src/micro_reader/backends/metamorph.py +658 -0
  40. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/metaxpress.py +3 -3
  41. micro_reader-0.2.0/src/micro_reader/backends/micromanager.py +578 -0
  42. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/mrc.py +119 -64
  43. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/nd2.py +8 -1
  44. micro_reader-0.2.0/src/micro_reader/backends/ndpis.py +206 -0
  45. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/oir.py +30 -8
  46. micro_reader-0.2.0/src/micro_reader/backends/omp2info.py +286 -0
  47. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/tiff.py +313 -45
  48. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/vsi.py +11 -2
  49. micro_reader-0.0.4/src/micro_reader/_errors.py +0 -31
  50. micro_reader-0.0.4/src/micro_reader/backends/_lif_metadata.py +0 -125
  51. micro_reader-0.0.4/src/micro_reader/backends/_tiff_variants.py +0 -239
  52. micro_reader-0.0.4/src/micro_reader/backends/ims.py +0 -409
  53. {micro_reader-0.0.4 → micro_reader-0.2.0}/.gitignore +0 -0
  54. {micro_reader-0.0.4 → micro_reader-0.2.0}/LICENSE +0 -0
  55. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_axes.py +0 -0
  56. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_cfb.py +0 -0
  57. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_index.py +0 -0
  58. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_jpeg_restarts.py +0 -0
  59. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_memory.py +0 -0
  60. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_parts.py +0 -0
  61. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/_stream.py +0 -0
  62. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/__init__.py +0 -0
  63. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/_ets.py +0 -0
  64. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/_nd2_structure.py +0 -0
  65. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/_vsi_tree.py +0 -0
  66. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/dv.py +0 -0
  67. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/oif.py +0 -0
  68. {micro_reader-0.0.4 → micro_reader-0.2.0}/src/micro_reader/backends/raster.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: micro-reader
3
- Version: 0.0.4
3
+ Version: 0.2.0
4
4
  Summary: Low-level, memory-bounded pixel reading for microscopy formats: read exactly the rectangle you ask for.
5
5
  Project-URL: Homepage, https://github.com/bugraoezdemir/micro-reader
6
6
  Project-URL: Source, https://github.com/bugraoezdemir/micro-reader
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Programming Language :: Python :: 3.14
19
19
  Classifier: Topic :: Scientific/Engineering :: Image Processing
20
20
  Requires-Python: >=3.11
21
- Requires-Dist: micro-reader-codecs<0.1,>=0.0.1
21
+ Requires-Dist: micro-reader-codecs<0.1,>=0.0.2
22
22
  Requires-Dist: numpy>=1.24
23
23
  Requires-Dist: tifffile>=2025.5.21
24
24
  Provides-Extra: all
@@ -36,6 +36,8 @@ Requires-Dist: pylibczirw; (python_version < '3.14') and extra == 'dev'
36
36
  Requires-Dist: pytest; extra == 'dev'
37
37
  Requires-Dist: readlif; extra == 'dev'
38
38
  Requires-Dist: zstandard; extra == 'dev'
39
+ Provides-Extra: hdf5
40
+ Requires-Dist: h5py>=3.11; extra == 'hdf5'
39
41
  Provides-Extra: ims
40
42
  Requires-Dist: h5py>=3.11; extra == 'ims'
41
43
  Provides-Extra: test
@@ -75,6 +77,14 @@ pip install "micro-reader[ims]" # Imaris (.ims)
75
77
  pip install "micro-reader[codecs]" # additional codecs
76
78
  ```
77
79
 
80
+ ## Compatibility with eubi-bridge
81
+
82
+ micro-reader 0.1.0 renamed the image index `scene` to `series`. eubi-bridge 0.1.3 to 0.2.x and eubi-bridge-lite below 0.3.0 still read `scene`, so `import micro_reader` refuses to load next to them. It raises an `ImportError` that names the installed eubi version and the two ways out: upgrade eubi (`pip install -U 'eubi-bridge>=0.3.0'`, or the same for `eubi-bridge-lite`), or keep that eubi with the micro-reader it was built for (`pip install 'micro-reader<0.1'`). The check reads the versions of the installed packages; it never imports eubi. An editable install of eubi is checked like any other: its recorded version can be out of date, so the message then says to reinstall it.
83
+
84
+ To skip the check, set the environment variable `MICRO_READER_SKIP_EUBI_CHECK=1`. Only the value `1` skips it; any other value keeps the check. micro-reader then warns once that the check was skipped. This is meant for work on an eubi checkout, not for normal use.
85
+
86
+ The check will be removed when every eubi-bridge / eubi-bridge-lite line below 0.3.0 has left the support window, checked by the release version matrix; not before.
87
+
78
88
  ## Quick start
79
89
 
80
90
  ```python
@@ -116,7 +126,7 @@ print(image.stats.over_read)
116
126
 
117
127
  * **File**: the opened microscopy file
118
128
  * **Image**: one image or frame that can be read as an array
119
- * **Index**: identifies images that are separated by dimensions such as scene, tile, view, or emission wavelength
129
+ * **Index**: identifies images that are separated by dimensions such as series, tile, view, or emission wavelength
120
130
 
121
131
  The key distinction is:
122
132
 
@@ -169,7 +179,7 @@ Each image has an index describing where it came from:
169
179
 
170
180
  ```python
171
181
  image.index
172
- # {"scene": 0, "tile": 3, "view": 0}
182
+ # {"series": 0, "tile": 3, "view": 0}
173
183
  ```
174
184
 
175
185
  You can inspect all indices in the file:
@@ -182,10 +192,10 @@ f.index_range
182
192
  And select images by index:
183
193
 
184
194
  ```python
185
- f.select(scene=1, view=0)
195
+ f.select(series=1, view=0)
186
196
  ```
187
197
 
188
- This returns the images matching the requested indices. For example, if a file contains several scenes, tiles, and views, selecting `scene=1, view=0` returns the tiles belonging to that scene and view.
198
+ This returns the images matching the requested indices. For example, if a file contains several series, tiles, and views, selecting `series=1, view=0` returns the tiles belonging to that series and view.
189
199
 
190
200
  ### Available index dimensions
191
201
 
@@ -196,7 +206,7 @@ plate
196
206
  acquisition
197
207
  well
198
208
  field
199
- scene
209
+ series
200
210
  tile
201
211
  rotation
202
212
  view
@@ -340,13 +350,13 @@ For example, a plain multi-page TIFF may contain 80 pages without saying whether
340
350
  f = micro_reader.open("stack.tif")
341
351
 
342
352
  print(f.index_range)
343
- # {"scene": 1, "sequence": 80}
353
+ # {"series": 1, "sequence": 80}
344
354
 
345
355
  print(len(f.images))
346
356
  # 80
347
357
 
348
358
  print(f.images[0].index)
349
- # {"scene": 0, "sequence": 0}
359
+ # {"series": 0, "sequence": 0}
350
360
 
351
361
  print(f.images[0].axes)
352
362
  # yx
@@ -392,10 +402,10 @@ Each image of a pyramidal file carries its resolution level in its index. In thi
392
402
 
393
403
  ```python
394
404
  print(f.index_range)
395
- # {"scene": 4, "resolution": 1}
405
+ # {"series": 4, "resolution": 1}
396
406
 
397
407
  print(f.images[0].index)
398
- # {"scene": 0, "resolution": 0}
408
+ # {"series": 0, "resolution": 0}
399
409
  ```
400
410
 
401
411
  `index_range` shows `"resolution": 1` because only the full-resolution level is in `f.images`.
@@ -403,15 +413,15 @@ print(f.images[0].index)
403
413
  Lower-resolution versions are available through the image via `image.resolutions`:
404
414
 
405
415
  ```python
406
- image_scene0 = f.images[0]
416
+ image_series0 = f.images[0]
407
417
 
408
- image_scene0.is_pyramidal
418
+ image_series0.is_pyramidal
409
419
  # True
410
420
 
411
- img_scene0_level2 = image_scene0.resolutions[2] # a lower-resolution image
421
+ img_series0_level2 = image_series0.resolutions[2] # a lower-resolution image
412
422
 
413
- img_scene0_level2.index
414
- # {"scene": 0, "resolution": 2}
423
+ img_series0_level2.index
424
+ # {"series": 0, "resolution": 2}
415
425
  ```
416
426
 
417
427
  If you prefer to expose every resolution level as an image directly under the `File` object:
@@ -423,37 +433,37 @@ f = micro_reader.open(
423
433
  )
424
434
 
425
435
  print(f.index_range)
426
- # {"scene": 4, "resolution": 6}
436
+ # {"series": 4, "resolution": 6}
427
437
 
428
- img_scene0_level2 = f.select(scene=0, resolution=2)[0]
438
+ img_series0_level2 = f.select(series=0, resolution=2)[0]
429
439
  ```
430
440
 
431
441
  Supported pyramids include:
432
442
 
433
443
  * **Imaris**: all stored levels
434
444
  * **TIFF**: OME-TIFF and whole-slide pyramids (SVS, NDPI, SCN, BIF, QPTIFF, Philips)
435
- * **CZI**: stored pyramids of whole scenes
445
+ * **CZI**: stored pyramids of whole series
436
446
 
437
447
  Other formats expose a single resolution level.
438
448
 
439
- CZI pyramids belong to whole scenes. Separately opened CZI mosaic tiles therefore do not have their own resolution levels.
449
+ CZI pyramids belong to whole series. Separately opened CZI mosaic tiles therefore do not have their own resolution levels.
440
450
 
441
451
  ## Mosaic tiles
442
452
 
443
- Mosaic tiles are separate images by default.
453
+ Mosaic tiles are separate images by default, each with its own position.
444
454
 
445
- For CZI files, you can instead request stitched scenes:
455
+ For CZI files and FluoView tiling sets (`.omp2info`), you can instead get one image per series, its tiles placed on one canvas:
446
456
 
447
457
  ```python
448
458
  f = micro_reader.open(
449
459
  path,
450
- tiles="stitched",
460
+ tiles="mosaic",
451
461
  )
452
462
  ```
453
463
 
454
- The tiles are composed according to the format's stitching information.
464
+ CZI tiles are placed by the file's own stitching information, FluoView tiles by the tiling set's grid (where tiles overlap, the later tile is on top; areas without a tile read as 0). Other formats with tiles raise an error for `tiles="mosaic"`.
455
465
 
456
- Currently, stitching is supported for **CZI only**.
466
+ `tiles="stitched"`, the name before 0.1.0, still works and warns.
457
467
 
458
468
  ## Plates
459
469
 
@@ -476,7 +486,7 @@ f.select(well=plate.well_index("B2"))
476
486
 
477
487
  `f.outline()` shows the plates, wells and fields of a file.
478
488
 
479
- Zeiss CZI plates are read as plates with `plates=True`, and as scenes otherwise:
489
+ Zeiss CZI plates are read as plates with `plates=True`, and as series otherwise:
480
490
 
481
491
  ```python
482
492
  f = micro_reader.open("plate.czi", plates=True)
@@ -557,13 +567,18 @@ The position is omitted when it cannot be determined reliably.
557
567
  | -------------------- | ----------------------------------------------------- |
558
568
  | **TIFF / BigTIFF** | TIFF, OME-TIFF, ImageJ, LSM, STK, Micro-Manager, whole-slide TIFFs |
559
569
  | **OME companion** | `.companion.ome` sets of OME-TIFF files |
560
- | **CZI** | Zeiss CZI, including mosaic tiles and stitched scenes |
570
+ | **CZI** | Zeiss CZI, including mosaic tiles (separate or on one canvas) |
561
571
  | **ND2** | Nikon ND2, including legacy JPEG 2000 ND2 |
562
572
  | **Leica** | LIF, LOF, LIFEXT, XLIF, XLEF, XLCF |
563
- | **OIR** | Olympus / Evident FluoView |
573
+ | **OIR** | Olympus / Evident FluoView, including tiling sets (`.omp2info`) |
564
574
  | **OIB / OIF** | Olympus FluoView FV1000 / FV1200 / FV3000 |
565
575
  | **VSI** | Olympus / Evident cellSens and VS120 / VS200 slide scanners |
566
- | **Imaris** | `.ims`, with the `[ims]` extra |
576
+ | **NDPIS** | Hamamatsu NanoZoomer fluorescence sets (one NDPI per channel) |
577
+ | **Imaris** | `.ims`, with the `[hdf5]` extra |
578
+ | **HDF5** | ilastik, BigDataViewer / BigStitcher, Luxendo, Fiji HDF5, with the `[hdf5]` extra |
579
+ | **ICS / IDS** | Image Cytometry Standard 1.0 and 2.0 (SVI Huygens and others) |
580
+ | **MetaMorph** | `.nd` acquisitions and their TIFF / STK files |
581
+ | **Micro-Manager 1.4**| image-per-file acquisitions (`metadata.txt` + one TIFF per plane) |
567
582
  | **DeltaVision** | `.dv`, `.r3d` (softWoRx, OMX, Priism) |
568
583
  | **MRC** | Common MRC modes and extended headers |
569
584
  | **Plates (HCS)** | Harmony, MetaXpress, IN Cell and CellVoyager plates |
@@ -584,13 +599,13 @@ Supported TIFF formats include:
584
599
  * Zeiss LSM
585
600
  * MetaMorph STK
586
601
  * Micro-Manager stacks (MMStack and NDTiff), also when one acquisition is spread over several files
587
- * Whole-slide TIFFs: Aperio SVS, Hamamatsu NDPI, Leica SCN, Ventana BIF, PerkinElmer / Akoya QPTIFF and Philips
602
+ * Whole-slide TIFFs: Aperio SVS, Hamamatsu NDPI, Leica SCN, Ventana / Roche BIF (VENTANA DP 200, iScan Coreo), PerkinElmer / Akoya QPTIFF and Philips
588
603
 
589
- Micro-Manager stage positions are scenes. NDTiff channel names and pixel sizes come from the dataset's index and frame metadata.
604
+ Micro-Manager stage positions are series. NDTiff channel names and pixel sizes come from the dataset's index and frame metadata.
590
605
 
591
- A whole-slide file gives the slide first, then the other pictures it stores as further scenes, as Bio-Formats lists them: `label` and `macro` (overview), and for some formats `thumbnail` (QPTIFF) or `probability` (BIF tissue map). Pixel sizes, positions and channel names come from each vendor's own metadata.
606
+ A whole-slide file gives the slide first, then the other pictures it stores as further series, as Bio-Formats lists them: `label` and `macro` (overview), and for some formats `thumbnail` (QPTIFF) or `probability` (BIF tissue map). Pixel sizes, positions and channel names come from each vendor's own metadata.
592
607
 
593
- Ventana BIF scans store overlapping tiles. They are composed as Roche's description of the format places them. Files from scanners other than the VENTANA DP 200 are not supported.
608
+ Ventana BIF scans store overlapping tiles. VENTANA DP 200 scans are composed as Roche's description of the format places them. iScan Coreo scans, which that description does not cover, are composed as OpenSlide shows them, with one difference: each tile starts at the nearest whole pixel and keeps its stored pixels, where OpenSlide interpolates to a sub-pixel position. Areas outside the scanned regions read as 0. Layouts that were not checked on real files (other EncodeInfo versions, several focal planes, overlapping scan areas) raise an error.
594
609
 
595
610
  Compressed TIFF data is decoded only for the strips or tiles needed by the requested region.
596
611
 
@@ -622,14 +637,16 @@ An OME companion file (`.companion.ome`) describes images stored in separate TIF
622
637
  f = micro_reader.open("data.companion.ome")
623
638
  ```
624
639
 
625
- Opening one of the TIFF files on its own reads only that file, with its pixel sizes, channels and position taken from the companion. If the companion is missing, the file is read without pixel sizes, with a `CompanionWarning`. A TIFF whose metadata lives in another OME-TIFF (instead of a `.companion.ome`) takes it from that file in the same way.
626
-
627
- Some OME-TIFF sets keep the full OME-XML in their TIFF files instead of a companion. Opening one of those files reads the whole set. To read only the planes stored in that file, with the set's metadata:
640
+ Opening one of the TIFF files of the set also reads the whole set, as if the companion had been opened: `f.path` is then the companion, and the companion's metadata is used. To read only that file, with its pixel sizes, channels and position taken from the companion:
628
641
 
629
642
  ```python
630
- f = micro_reader.open("set_t001.ome.tif", multifile=False)
643
+ f = micro_reader.open("data_t001.ome.tif", multifile=False)
631
644
  ```
632
645
 
646
+ If the companion is missing or does not list the file, opening the whole set raises an error that names `multifile=False`. With `multifile=False` the file is then read without pixel sizes, with a `CompanionWarning`. A TIFF whose metadata lives in another OME-TIFF (instead of a `.companion.ome`) works the same way, with that OME-TIFF in the companion's place.
647
+
648
+ Some OME-TIFF sets keep the full OME-XML in their TIFF files instead of a companion. Opening one of those files also reads the whole set, and `multifile=False` reads only the planes stored in that file, with the set's metadata.
649
+
633
650
  Micro-Manager stacks always open whole, also with `multifile=False`: they split their files by size, so one file does not hold a complete part of the image.
634
651
 
635
652
  ### CZI
@@ -637,12 +654,12 @@ Micro-Manager stacks always open whole, also with `multifile=False`: they split
637
654
  CZI files support:
638
655
 
639
656
  * mosaic tiles
640
- * scenes
657
+ * series
641
658
  * views
642
659
  * rotations
643
660
  * RGB
644
661
  * large files
645
- * stored scene pyramids
662
+ * stored series pyramids
646
663
 
647
664
  CZI-specific operations include:
648
665
 
@@ -693,6 +710,8 @@ These are represented using the common image/index model.
693
710
 
694
711
  Olympus / Evident FluoView OIR files are supported, including companion files and spectral scans.
695
712
 
713
+ A multi-area tiling set is opened through its index, `.omp2info`, or its folder: one image per tile, each at the stage position the index gives it (the tiles' own files record none), or one canvas per group with `tiles="mosaic"`. Positions follow the protocol's grid, not a registration. The grid step was derived from one sample, as the backend documents.
714
+
696
715
  ### Olympus OIB and OIF
697
716
 
698
717
  Older FluoView files come in two forms with the same content: an OIB is one file, an OIF is a `.oif` settings file plus a `.oif.files` folder with one TIFF per plane. Both open as one `t c z y x` image, with pixel sizes, z and time steps, channel names, colours and wavelengths. Opening any file in the `.oif.files` folder opens the OIF.
@@ -710,13 +729,40 @@ Opening the `_<name>_` folder, a `stack` folder or a file in it opens the `.vsi`
710
729
  Install Imaris support with:
711
730
 
712
731
  ```bash
713
- pip install "micro-reader[ims]"
732
+ pip install "micro-reader[hdf5]"
714
733
  ```
715
734
 
735
+ (`[ims]` is the extra's former name and still works.)
736
+
716
737
  Imaris resolution level 0 is exposed at the actual image size, with Imaris chunk padding removed.
717
738
 
718
739
  Chunked compression is decoded in parallel.
719
740
 
741
+ ### HDF5: ilastik, BigDataViewer, Luxendo, Fiji
742
+
743
+ These need the `[hdf5]` extra as well.
744
+
745
+ * **ilastik**: every dataset with ilastik's `axistags` (its exports, its input files, steinbock's `img`) is one image, in the dataset's own axis order. Pixel sizes are read where ilastik recorded units (`axis_units`, since 2025-09).
746
+ * **BigDataViewer / BigStitcher**: the XML with its HDF5 file (also partitioned). One image per tile, angle and illumination, channels on `c` and time points on `t`, with the stored resolution levels. Opening the HDF5 file opens its XML.
747
+ * **Luxendo / Bruker light-sheet** (`.lux.h5`): one stack per file. A whole acquisition opens through the Imaris file Luxendo writes next to it.
748
+ * **Fiji HDF5** (the Vibez plugin): datasets with `element_size_um`; `t<n>/channel<n>` datasets make one `t c z y x` image.
749
+
750
+ ### ICS / IDS
751
+
752
+ ICS 1.0 (an `.ics` header with an `.ids` pixel file; opening either opens the image) and ICS 2.0 (one file), as written by SVI Huygens and others. Gzip-compressed pixels are read without decompressing the whole file. Images that store rows bottom-up (`coordinates cartesian`) are returned top-down, as Bio-Formats does.
753
+
754
+ ### MetaMorph .nd
755
+
756
+ A MetaMorph multi-dimensional acquisition: an `.nd` file and the TIFF / STK files named after it. One image per stage position (`series`), `t c z y x`, channels named by the wavelengths. Opening the `.nd` file, any of its files or its folder opens the whole set. The stage coordinates the files record are kept as `Metadata.stage_position`, not as a position: which point of the field they mark is not recorded.
757
+
758
+ ### Micro-Manager 1.4
759
+
760
+ Image-per-file acquisitions (Micro-Manager 1.4 and the 2.0 betas): a folder per stage position with a `metadata.txt` and one TIFF per plane. One image per stage position, `t c z y x`, with channel names and colours, pixel sizes and the z step. Opening any file or folder of the acquisition opens the whole acquisition.
761
+
762
+ ### Hamamatsu NDPIS
763
+
764
+ An `.ndpis` set lists one NDPI file per fluorescence channel. Opened, it is one slide image with one channel per file, at every stored resolution level; channels are named by their filter set. Each NDPI file still opens alone as an ordinary slide.
765
+
720
766
  ### DeltaVision
721
767
 
722
768
  DeltaVision files (`.dv`, `.r3d`, `.r3d_d3d`, also deconvolved and projected ones) are recognised by their content, whatever their extension. The image keeps the file's own order of time, waves and z (for example `ctzyx`).
@@ -23,6 +23,14 @@ pip install "micro-reader[ims]" # Imaris (.ims)
23
23
  pip install "micro-reader[codecs]" # additional codecs
24
24
  ```
25
25
 
26
+ ## Compatibility with eubi-bridge
27
+
28
+ micro-reader 0.1.0 renamed the image index `scene` to `series`. eubi-bridge 0.1.3 to 0.2.x and eubi-bridge-lite below 0.3.0 still read `scene`, so `import micro_reader` refuses to load next to them. It raises an `ImportError` that names the installed eubi version and the two ways out: upgrade eubi (`pip install -U 'eubi-bridge>=0.3.0'`, or the same for `eubi-bridge-lite`), or keep that eubi with the micro-reader it was built for (`pip install 'micro-reader<0.1'`). The check reads the versions of the installed packages; it never imports eubi. An editable install of eubi is checked like any other: its recorded version can be out of date, so the message then says to reinstall it.
29
+
30
+ To skip the check, set the environment variable `MICRO_READER_SKIP_EUBI_CHECK=1`. Only the value `1` skips it; any other value keeps the check. micro-reader then warns once that the check was skipped. This is meant for work on an eubi checkout, not for normal use.
31
+
32
+ The check will be removed when every eubi-bridge / eubi-bridge-lite line below 0.3.0 has left the support window, checked by the release version matrix; not before.
33
+
26
34
  ## Quick start
27
35
 
28
36
  ```python
@@ -64,7 +72,7 @@ print(image.stats.over_read)
64
72
 
65
73
  * **File**: the opened microscopy file
66
74
  * **Image**: one image or frame that can be read as an array
67
- * **Index**: identifies images that are separated by dimensions such as scene, tile, view, or emission wavelength
75
+ * **Index**: identifies images that are separated by dimensions such as series, tile, view, or emission wavelength
68
76
 
69
77
  The key distinction is:
70
78
 
@@ -117,7 +125,7 @@ Each image has an index describing where it came from:
117
125
 
118
126
  ```python
119
127
  image.index
120
- # {"scene": 0, "tile": 3, "view": 0}
128
+ # {"series": 0, "tile": 3, "view": 0}
121
129
  ```
122
130
 
123
131
  You can inspect all indices in the file:
@@ -130,10 +138,10 @@ f.index_range
130
138
  And select images by index:
131
139
 
132
140
  ```python
133
- f.select(scene=1, view=0)
141
+ f.select(series=1, view=0)
134
142
  ```
135
143
 
136
- This returns the images matching the requested indices. For example, if a file contains several scenes, tiles, and views, selecting `scene=1, view=0` returns the tiles belonging to that scene and view.
144
+ This returns the images matching the requested indices. For example, if a file contains several series, tiles, and views, selecting `series=1, view=0` returns the tiles belonging to that series and view.
137
145
 
138
146
  ### Available index dimensions
139
147
 
@@ -144,7 +152,7 @@ plate
144
152
  acquisition
145
153
  well
146
154
  field
147
- scene
155
+ series
148
156
  tile
149
157
  rotation
150
158
  view
@@ -288,13 +296,13 @@ For example, a plain multi-page TIFF may contain 80 pages without saying whether
288
296
  f = micro_reader.open("stack.tif")
289
297
 
290
298
  print(f.index_range)
291
- # {"scene": 1, "sequence": 80}
299
+ # {"series": 1, "sequence": 80}
292
300
 
293
301
  print(len(f.images))
294
302
  # 80
295
303
 
296
304
  print(f.images[0].index)
297
- # {"scene": 0, "sequence": 0}
305
+ # {"series": 0, "sequence": 0}
298
306
 
299
307
  print(f.images[0].axes)
300
308
  # yx
@@ -340,10 +348,10 @@ Each image of a pyramidal file carries its resolution level in its index. In thi
340
348
 
341
349
  ```python
342
350
  print(f.index_range)
343
- # {"scene": 4, "resolution": 1}
351
+ # {"series": 4, "resolution": 1}
344
352
 
345
353
  print(f.images[0].index)
346
- # {"scene": 0, "resolution": 0}
354
+ # {"series": 0, "resolution": 0}
347
355
  ```
348
356
 
349
357
  `index_range` shows `"resolution": 1` because only the full-resolution level is in `f.images`.
@@ -351,15 +359,15 @@ print(f.images[0].index)
351
359
  Lower-resolution versions are available through the image via `image.resolutions`:
352
360
 
353
361
  ```python
354
- image_scene0 = f.images[0]
362
+ image_series0 = f.images[0]
355
363
 
356
- image_scene0.is_pyramidal
364
+ image_series0.is_pyramidal
357
365
  # True
358
366
 
359
- img_scene0_level2 = image_scene0.resolutions[2] # a lower-resolution image
367
+ img_series0_level2 = image_series0.resolutions[2] # a lower-resolution image
360
368
 
361
- img_scene0_level2.index
362
- # {"scene": 0, "resolution": 2}
369
+ img_series0_level2.index
370
+ # {"series": 0, "resolution": 2}
363
371
  ```
364
372
 
365
373
  If you prefer to expose every resolution level as an image directly under the `File` object:
@@ -371,37 +379,37 @@ f = micro_reader.open(
371
379
  )
372
380
 
373
381
  print(f.index_range)
374
- # {"scene": 4, "resolution": 6}
382
+ # {"series": 4, "resolution": 6}
375
383
 
376
- img_scene0_level2 = f.select(scene=0, resolution=2)[0]
384
+ img_series0_level2 = f.select(series=0, resolution=2)[0]
377
385
  ```
378
386
 
379
387
  Supported pyramids include:
380
388
 
381
389
  * **Imaris**: all stored levels
382
390
  * **TIFF**: OME-TIFF and whole-slide pyramids (SVS, NDPI, SCN, BIF, QPTIFF, Philips)
383
- * **CZI**: stored pyramids of whole scenes
391
+ * **CZI**: stored pyramids of whole series
384
392
 
385
393
  Other formats expose a single resolution level.
386
394
 
387
- CZI pyramids belong to whole scenes. Separately opened CZI mosaic tiles therefore do not have their own resolution levels.
395
+ CZI pyramids belong to whole series. Separately opened CZI mosaic tiles therefore do not have their own resolution levels.
388
396
 
389
397
  ## Mosaic tiles
390
398
 
391
- Mosaic tiles are separate images by default.
399
+ Mosaic tiles are separate images by default, each with its own position.
392
400
 
393
- For CZI files, you can instead request stitched scenes:
401
+ For CZI files and FluoView tiling sets (`.omp2info`), you can instead get one image per series, its tiles placed on one canvas:
394
402
 
395
403
  ```python
396
404
  f = micro_reader.open(
397
405
  path,
398
- tiles="stitched",
406
+ tiles="mosaic",
399
407
  )
400
408
  ```
401
409
 
402
- The tiles are composed according to the format's stitching information.
410
+ CZI tiles are placed by the file's own stitching information, FluoView tiles by the tiling set's grid (where tiles overlap, the later tile is on top; areas without a tile read as 0). Other formats with tiles raise an error for `tiles="mosaic"`.
403
411
 
404
- Currently, stitching is supported for **CZI only**.
412
+ `tiles="stitched"`, the name before 0.1.0, still works and warns.
405
413
 
406
414
  ## Plates
407
415
 
@@ -424,7 +432,7 @@ f.select(well=plate.well_index("B2"))
424
432
 
425
433
  `f.outline()` shows the plates, wells and fields of a file.
426
434
 
427
- Zeiss CZI plates are read as plates with `plates=True`, and as scenes otherwise:
435
+ Zeiss CZI plates are read as plates with `plates=True`, and as series otherwise:
428
436
 
429
437
  ```python
430
438
  f = micro_reader.open("plate.czi", plates=True)
@@ -505,13 +513,18 @@ The position is omitted when it cannot be determined reliably.
505
513
  | -------------------- | ----------------------------------------------------- |
506
514
  | **TIFF / BigTIFF** | TIFF, OME-TIFF, ImageJ, LSM, STK, Micro-Manager, whole-slide TIFFs |
507
515
  | **OME companion** | `.companion.ome` sets of OME-TIFF files |
508
- | **CZI** | Zeiss CZI, including mosaic tiles and stitched scenes |
516
+ | **CZI** | Zeiss CZI, including mosaic tiles (separate or on one canvas) |
509
517
  | **ND2** | Nikon ND2, including legacy JPEG 2000 ND2 |
510
518
  | **Leica** | LIF, LOF, LIFEXT, XLIF, XLEF, XLCF |
511
- | **OIR** | Olympus / Evident FluoView |
519
+ | **OIR** | Olympus / Evident FluoView, including tiling sets (`.omp2info`) |
512
520
  | **OIB / OIF** | Olympus FluoView FV1000 / FV1200 / FV3000 |
513
521
  | **VSI** | Olympus / Evident cellSens and VS120 / VS200 slide scanners |
514
- | **Imaris** | `.ims`, with the `[ims]` extra |
522
+ | **NDPIS** | Hamamatsu NanoZoomer fluorescence sets (one NDPI per channel) |
523
+ | **Imaris** | `.ims`, with the `[hdf5]` extra |
524
+ | **HDF5** | ilastik, BigDataViewer / BigStitcher, Luxendo, Fiji HDF5, with the `[hdf5]` extra |
525
+ | **ICS / IDS** | Image Cytometry Standard 1.0 and 2.0 (SVI Huygens and others) |
526
+ | **MetaMorph** | `.nd` acquisitions and their TIFF / STK files |
527
+ | **Micro-Manager 1.4**| image-per-file acquisitions (`metadata.txt` + one TIFF per plane) |
515
528
  | **DeltaVision** | `.dv`, `.r3d` (softWoRx, OMX, Priism) |
516
529
  | **MRC** | Common MRC modes and extended headers |
517
530
  | **Plates (HCS)** | Harmony, MetaXpress, IN Cell and CellVoyager plates |
@@ -532,13 +545,13 @@ Supported TIFF formats include:
532
545
  * Zeiss LSM
533
546
  * MetaMorph STK
534
547
  * Micro-Manager stacks (MMStack and NDTiff), also when one acquisition is spread over several files
535
- * Whole-slide TIFFs: Aperio SVS, Hamamatsu NDPI, Leica SCN, Ventana BIF, PerkinElmer / Akoya QPTIFF and Philips
548
+ * Whole-slide TIFFs: Aperio SVS, Hamamatsu NDPI, Leica SCN, Ventana / Roche BIF (VENTANA DP 200, iScan Coreo), PerkinElmer / Akoya QPTIFF and Philips
536
549
 
537
- Micro-Manager stage positions are scenes. NDTiff channel names and pixel sizes come from the dataset's index and frame metadata.
550
+ Micro-Manager stage positions are series. NDTiff channel names and pixel sizes come from the dataset's index and frame metadata.
538
551
 
539
- A whole-slide file gives the slide first, then the other pictures it stores as further scenes, as Bio-Formats lists them: `label` and `macro` (overview), and for some formats `thumbnail` (QPTIFF) or `probability` (BIF tissue map). Pixel sizes, positions and channel names come from each vendor's own metadata.
552
+ A whole-slide file gives the slide first, then the other pictures it stores as further series, as Bio-Formats lists them: `label` and `macro` (overview), and for some formats `thumbnail` (QPTIFF) or `probability` (BIF tissue map). Pixel sizes, positions and channel names come from each vendor's own metadata.
540
553
 
541
- Ventana BIF scans store overlapping tiles. They are composed as Roche's description of the format places them. Files from scanners other than the VENTANA DP 200 are not supported.
554
+ Ventana BIF scans store overlapping tiles. VENTANA DP 200 scans are composed as Roche's description of the format places them. iScan Coreo scans, which that description does not cover, are composed as OpenSlide shows them, with one difference: each tile starts at the nearest whole pixel and keeps its stored pixels, where OpenSlide interpolates to a sub-pixel position. Areas outside the scanned regions read as 0. Layouts that were not checked on real files (other EncodeInfo versions, several focal planes, overlapping scan areas) raise an error.
542
555
 
543
556
  Compressed TIFF data is decoded only for the strips or tiles needed by the requested region.
544
557
 
@@ -570,14 +583,16 @@ An OME companion file (`.companion.ome`) describes images stored in separate TIF
570
583
  f = micro_reader.open("data.companion.ome")
571
584
  ```
572
585
 
573
- Opening one of the TIFF files on its own reads only that file, with its pixel sizes, channels and position taken from the companion. If the companion is missing, the file is read without pixel sizes, with a `CompanionWarning`. A TIFF whose metadata lives in another OME-TIFF (instead of a `.companion.ome`) takes it from that file in the same way.
574
-
575
- Some OME-TIFF sets keep the full OME-XML in their TIFF files instead of a companion. Opening one of those files reads the whole set. To read only the planes stored in that file, with the set's metadata:
586
+ Opening one of the TIFF files of the set also reads the whole set, as if the companion had been opened: `f.path` is then the companion, and the companion's metadata is used. To read only that file, with its pixel sizes, channels and position taken from the companion:
576
587
 
577
588
  ```python
578
- f = micro_reader.open("set_t001.ome.tif", multifile=False)
589
+ f = micro_reader.open("data_t001.ome.tif", multifile=False)
579
590
  ```
580
591
 
592
+ If the companion is missing or does not list the file, opening the whole set raises an error that names `multifile=False`. With `multifile=False` the file is then read without pixel sizes, with a `CompanionWarning`. A TIFF whose metadata lives in another OME-TIFF (instead of a `.companion.ome`) works the same way, with that OME-TIFF in the companion's place.
593
+
594
+ Some OME-TIFF sets keep the full OME-XML in their TIFF files instead of a companion. Opening one of those files also reads the whole set, and `multifile=False` reads only the planes stored in that file, with the set's metadata.
595
+
581
596
  Micro-Manager stacks always open whole, also with `multifile=False`: they split their files by size, so one file does not hold a complete part of the image.
582
597
 
583
598
  ### CZI
@@ -585,12 +600,12 @@ Micro-Manager stacks always open whole, also with `multifile=False`: they split
585
600
  CZI files support:
586
601
 
587
602
  * mosaic tiles
588
- * scenes
603
+ * series
589
604
  * views
590
605
  * rotations
591
606
  * RGB
592
607
  * large files
593
- * stored scene pyramids
608
+ * stored series pyramids
594
609
 
595
610
  CZI-specific operations include:
596
611
 
@@ -641,6 +656,8 @@ These are represented using the common image/index model.
641
656
 
642
657
  Olympus / Evident FluoView OIR files are supported, including companion files and spectral scans.
643
658
 
659
+ A multi-area tiling set is opened through its index, `.omp2info`, or its folder: one image per tile, each at the stage position the index gives it (the tiles' own files record none), or one canvas per group with `tiles="mosaic"`. Positions follow the protocol's grid, not a registration. The grid step was derived from one sample, as the backend documents.
660
+
644
661
  ### Olympus OIB and OIF
645
662
 
646
663
  Older FluoView files come in two forms with the same content: an OIB is one file, an OIF is a `.oif` settings file plus a `.oif.files` folder with one TIFF per plane. Both open as one `t c z y x` image, with pixel sizes, z and time steps, channel names, colours and wavelengths. Opening any file in the `.oif.files` folder opens the OIF.
@@ -658,13 +675,40 @@ Opening the `_<name>_` folder, a `stack` folder or a file in it opens the `.vsi`
658
675
  Install Imaris support with:
659
676
 
660
677
  ```bash
661
- pip install "micro-reader[ims]"
678
+ pip install "micro-reader[hdf5]"
662
679
  ```
663
680
 
681
+ (`[ims]` is the extra's former name and still works.)
682
+
664
683
  Imaris resolution level 0 is exposed at the actual image size, with Imaris chunk padding removed.
665
684
 
666
685
  Chunked compression is decoded in parallel.
667
686
 
687
+ ### HDF5: ilastik, BigDataViewer, Luxendo, Fiji
688
+
689
+ These need the `[hdf5]` extra as well.
690
+
691
+ * **ilastik**: every dataset with ilastik's `axistags` (its exports, its input files, steinbock's `img`) is one image, in the dataset's own axis order. Pixel sizes are read where ilastik recorded units (`axis_units`, since 2025-09).
692
+ * **BigDataViewer / BigStitcher**: the XML with its HDF5 file (also partitioned). One image per tile, angle and illumination, channels on `c` and time points on `t`, with the stored resolution levels. Opening the HDF5 file opens its XML.
693
+ * **Luxendo / Bruker light-sheet** (`.lux.h5`): one stack per file. A whole acquisition opens through the Imaris file Luxendo writes next to it.
694
+ * **Fiji HDF5** (the Vibez plugin): datasets with `element_size_um`; `t<n>/channel<n>` datasets make one `t c z y x` image.
695
+
696
+ ### ICS / IDS
697
+
698
+ ICS 1.0 (an `.ics` header with an `.ids` pixel file; opening either opens the image) and ICS 2.0 (one file), as written by SVI Huygens and others. Gzip-compressed pixels are read without decompressing the whole file. Images that store rows bottom-up (`coordinates cartesian`) are returned top-down, as Bio-Formats does.
699
+
700
+ ### MetaMorph .nd
701
+
702
+ A MetaMorph multi-dimensional acquisition: an `.nd` file and the TIFF / STK files named after it. One image per stage position (`series`), `t c z y x`, channels named by the wavelengths. Opening the `.nd` file, any of its files or its folder opens the whole set. The stage coordinates the files record are kept as `Metadata.stage_position`, not as a position: which point of the field they mark is not recorded.
703
+
704
+ ### Micro-Manager 1.4
705
+
706
+ Image-per-file acquisitions (Micro-Manager 1.4 and the 2.0 betas): a folder per stage position with a `metadata.txt` and one TIFF per plane. One image per stage position, `t c z y x`, with channel names and colours, pixel sizes and the z step. Opening any file or folder of the acquisition opens the whole acquisition.
707
+
708
+ ### Hamamatsu NDPIS
709
+
710
+ An `.ndpis` set lists one NDPI file per fluorescence channel. Opened, it is one slide image with one channel per file, at every stored resolution level; channels are named by their filter set. Each NDPI file still opens alone as an ordinary slide.
711
+
668
712
  ### DeltaVision
669
713
 
670
714
  DeltaVision files (`.dv`, `.r3d`, `.r3d_d3d`, also deconvolved and projected ones) are recognised by their content, whatever their extension. The image keeps the file's own order of time, waves and z (for example `ctzyx`).
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "micro-reader"
9
- version = "0.0.4"
9
+ version = "0.2.0"
10
10
  description = "Low-level, memory-bounded pixel reading for microscopy formats: read exactly the rectangle you ask for."
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.11"
@@ -29,7 +29,7 @@ classifiers = [
29
29
  # TIFF covers most microscopy images, so it is not an extra (Bugra,
30
30
  # 2026-10-01) until micro-reader parses TIFF itself (post-0.0.1). The floor
31
31
  # matches eubi-bridge's (tifffile>=2025.5.21), so both install together.
32
- dependencies = ["numpy>=1.24", "micro-reader-codecs>=0.0.1,<0.1", "tifffile>=2025.5.21"]
32
+ dependencies = ["numpy>=1.24", "micro-reader-codecs>=0.0.2,<0.1", "tifffile>=2025.5.21"]
33
33
 
34
34
  [project.urls]
35
35
  Homepage = "https://github.com/bugraoezdemir/micro-reader"
@@ -37,9 +37,11 @@ Source = "https://github.com/bugraoezdemir/micro-reader"
37
37
  Issues = "https://github.com/bugraoezdemir/micro-reader/issues"
38
38
 
39
39
  [project.optional-dependencies]
40
- ims = ["h5py>=3.11"] # first h5py for numpy 2; chunk offsets checked against user blocks
40
+ # HDF5 files: Imaris, ilastik, BigDataViewer; `ims` is the older name, kept
41
+ hdf5 = ["h5py>=3.11"] # first h5py for numpy 2; chunk offsets checked against user blocks
42
+ ims = ["micro-reader[hdf5]"]
41
43
  codecs = ["imagecodecs"]
42
- all = ["micro-reader[ims,codecs]"]
44
+ all = ["micro-reader[hdf5,codecs]"]
43
45
  # the reference readers and encoders the tests compare with: never shipped
44
46
  # (readlif is GPL-3, pylibCZIrw LGPL-3: test-only, PLAN.md "Dependency policy")
45
47
  test = ["pytest", "pillow", "h5py>=3.11", "imagecodecs", "zstandard", "nd2", "readlif", "liffile",