careamics 0.0.19__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.
Files changed (279) hide show
  1. careamics/__init__.py +24 -0
  2. careamics/careamist.py +961 -0
  3. careamics/cli/__init__.py +5 -0
  4. careamics/cli/conf.py +394 -0
  5. careamics/cli/main.py +234 -0
  6. careamics/cli/utils.py +27 -0
  7. careamics/config/__init__.py +66 -0
  8. careamics/config/algorithms/__init__.py +21 -0
  9. careamics/config/algorithms/care_algorithm_config.py +122 -0
  10. careamics/config/algorithms/hdn_algorithm_config.py +103 -0
  11. careamics/config/algorithms/microsplit_algorithm_config.py +103 -0
  12. careamics/config/algorithms/n2n_algorithm_config.py +115 -0
  13. careamics/config/algorithms/n2v_algorithm_config.py +296 -0
  14. careamics/config/algorithms/pn2v_algorithm_config.py +301 -0
  15. careamics/config/algorithms/unet_algorithm_config.py +91 -0
  16. careamics/config/algorithms/vae_algorithm_config.py +178 -0
  17. careamics/config/architectures/__init__.py +7 -0
  18. careamics/config/architectures/architecture_config.py +37 -0
  19. careamics/config/architectures/lvae_config.py +262 -0
  20. careamics/config/architectures/unet_config.py +125 -0
  21. careamics/config/configuration.py +367 -0
  22. careamics/config/configuration_factories.py +2400 -0
  23. careamics/config/data/__init__.py +27 -0
  24. careamics/config/data/data_config.py +472 -0
  25. careamics/config/data/inference_config.py +237 -0
  26. careamics/config/data/ng_data_config.py +1038 -0
  27. careamics/config/data/patch_filter/__init__.py +15 -0
  28. careamics/config/data/patch_filter/filter_config.py +16 -0
  29. careamics/config/data/patch_filter/mask_filter_config.py +17 -0
  30. careamics/config/data/patch_filter/max_filter_config.py +15 -0
  31. careamics/config/data/patch_filter/meanstd_filter_config.py +18 -0
  32. careamics/config/data/patch_filter/shannon_filter_config.py +15 -0
  33. careamics/config/data/patching_strategies/__init__.py +15 -0
  34. careamics/config/data/patching_strategies/_overlapping_patched_config.py +102 -0
  35. careamics/config/data/patching_strategies/_patched_config.py +56 -0
  36. careamics/config/data/patching_strategies/random_patching_config.py +45 -0
  37. careamics/config/data/patching_strategies/sequential_patching_config.py +25 -0
  38. careamics/config/data/patching_strategies/tiled_patching_config.py +40 -0
  39. careamics/config/data/patching_strategies/whole_patching_config.py +12 -0
  40. careamics/config/data/tile_information.py +65 -0
  41. careamics/config/lightning/__init__.py +15 -0
  42. careamics/config/lightning/callbacks/__init__.py +8 -0
  43. careamics/config/lightning/callbacks/callback_config.py +116 -0
  44. careamics/config/lightning/optimizer_configs.py +186 -0
  45. careamics/config/lightning/training_config.py +70 -0
  46. careamics/config/losses/__init__.py +8 -0
  47. careamics/config/losses/loss_config.py +60 -0
  48. careamics/config/ng_configs/__init__.py +5 -0
  49. careamics/config/ng_configs/n2v_configuration.py +64 -0
  50. careamics/config/ng_configs/ng_configuration.py +256 -0
  51. careamics/config/ng_factories/__init__.py +9 -0
  52. careamics/config/ng_factories/algorithm_factory.py +120 -0
  53. careamics/config/ng_factories/data_factory.py +154 -0
  54. careamics/config/ng_factories/n2v_factory.py +256 -0
  55. careamics/config/ng_factories/training_factory.py +69 -0
  56. careamics/config/noise_model/__init__.py +12 -0
  57. careamics/config/noise_model/likelihood_config.py +60 -0
  58. careamics/config/noise_model/noise_model_config.py +149 -0
  59. careamics/config/support/__init__.py +31 -0
  60. careamics/config/support/supported_activations.py +27 -0
  61. careamics/config/support/supported_algorithms.py +40 -0
  62. careamics/config/support/supported_architectures.py +13 -0
  63. careamics/config/support/supported_data.py +122 -0
  64. careamics/config/support/supported_filters.py +17 -0
  65. careamics/config/support/supported_loggers.py +10 -0
  66. careamics/config/support/supported_losses.py +32 -0
  67. careamics/config/support/supported_optimizers.py +57 -0
  68. careamics/config/support/supported_patching_strategies.py +22 -0
  69. careamics/config/support/supported_pixel_manipulations.py +15 -0
  70. careamics/config/support/supported_struct_axis.py +21 -0
  71. careamics/config/support/supported_transforms.py +12 -0
  72. careamics/config/transformations/__init__.py +22 -0
  73. careamics/config/transformations/n2v_manipulate_config.py +79 -0
  74. careamics/config/transformations/normalize_config.py +59 -0
  75. careamics/config/transformations/transform_config.py +45 -0
  76. careamics/config/transformations/transform_unions.py +29 -0
  77. careamics/config/transformations/xy_flip_config.py +43 -0
  78. careamics/config/transformations/xy_random_rotate90_config.py +35 -0
  79. careamics/config/utils/__init__.py +8 -0
  80. careamics/config/utils/configuration_io.py +85 -0
  81. careamics/config/validators/__init__.py +18 -0
  82. careamics/config/validators/axes_validators.py +90 -0
  83. careamics/config/validators/model_validators.py +84 -0
  84. careamics/config/validators/patch_validators.py +55 -0
  85. careamics/conftest.py +39 -0
  86. careamics/dataset/__init__.py +17 -0
  87. careamics/dataset/dataset_utils/__init__.py +19 -0
  88. careamics/dataset/dataset_utils/dataset_utils.py +118 -0
  89. careamics/dataset/dataset_utils/file_utils.py +141 -0
  90. careamics/dataset/dataset_utils/iterate_over_files.py +84 -0
  91. careamics/dataset/dataset_utils/running_stats.py +189 -0
  92. careamics/dataset/in_memory_dataset.py +303 -0
  93. careamics/dataset/in_memory_pred_dataset.py +88 -0
  94. careamics/dataset/in_memory_tiled_pred_dataset.py +131 -0
  95. careamics/dataset/iterable_dataset.py +294 -0
  96. careamics/dataset/iterable_pred_dataset.py +121 -0
  97. careamics/dataset/iterable_tiled_pred_dataset.py +141 -0
  98. careamics/dataset/patching/__init__.py +1 -0
  99. careamics/dataset/patching/patching.py +300 -0
  100. careamics/dataset/patching/random_patching.py +110 -0
  101. careamics/dataset/patching/sequential_patching.py +212 -0
  102. careamics/dataset/patching/validate_patch_dimension.py +64 -0
  103. careamics/dataset/tiling/__init__.py +10 -0
  104. careamics/dataset/tiling/collate_tiles.py +33 -0
  105. careamics/dataset/tiling/lvae_tiled_patching.py +375 -0
  106. careamics/dataset/tiling/tiled_patching.py +166 -0
  107. careamics/dataset_ng/README.md +212 -0
  108. careamics/dataset_ng/__init__.py +0 -0
  109. careamics/dataset_ng/dataset.py +365 -0
  110. careamics/dataset_ng/demos/bsd68_demo.ipynb +361 -0
  111. careamics/dataset_ng/demos/bsd68_zarr_demo.ipynb +453 -0
  112. careamics/dataset_ng/demos/care_U2OS_demo.ipynb +330 -0
  113. careamics/dataset_ng/demos/demo_custom_image_stack.ipynb +736 -0
  114. careamics/dataset_ng/demos/demo_datamodule.ipynb +447 -0
  115. careamics/dataset_ng/demos/demo_dataset.ipynb +278 -0
  116. careamics/dataset_ng/demos/demo_patch_extractor.py +51 -0
  117. careamics/dataset_ng/demos/mouse_nuclei_demo.ipynb +293 -0
  118. careamics/dataset_ng/factory.py +180 -0
  119. careamics/dataset_ng/grouped_index_sampler.py +73 -0
  120. careamics/dataset_ng/image_stack/__init__.py +14 -0
  121. careamics/dataset_ng/image_stack/czi_image_stack.py +396 -0
  122. careamics/dataset_ng/image_stack/file_image_stack.py +140 -0
  123. careamics/dataset_ng/image_stack/image_stack_protocol.py +93 -0
  124. careamics/dataset_ng/image_stack/image_utils/__init__.py +6 -0
  125. careamics/dataset_ng/image_stack/image_utils/image_stack_utils.py +125 -0
  126. careamics/dataset_ng/image_stack/in_memory_image_stack.py +93 -0
  127. careamics/dataset_ng/image_stack/zarr_image_stack.py +170 -0
  128. careamics/dataset_ng/image_stack_loader/__init__.py +19 -0
  129. careamics/dataset_ng/image_stack_loader/image_stack_loader_protocol.py +70 -0
  130. careamics/dataset_ng/image_stack_loader/image_stack_loaders.py +273 -0
  131. careamics/dataset_ng/image_stack_loader/zarr_utils.py +130 -0
  132. careamics/dataset_ng/legacy_interoperability.py +175 -0
  133. careamics/dataset_ng/microsplit_input_synth.py +377 -0
  134. careamics/dataset_ng/patch_extractor/__init__.py +7 -0
  135. careamics/dataset_ng/patch_extractor/limit_file_extractor.py +50 -0
  136. careamics/dataset_ng/patch_extractor/patch_construction.py +151 -0
  137. careamics/dataset_ng/patch_extractor/patch_extractor.py +117 -0
  138. careamics/dataset_ng/patch_filter/__init__.py +20 -0
  139. careamics/dataset_ng/patch_filter/coordinate_filter_protocol.py +27 -0
  140. careamics/dataset_ng/patch_filter/filter_factory.py +95 -0
  141. careamics/dataset_ng/patch_filter/mask_filter.py +96 -0
  142. careamics/dataset_ng/patch_filter/max_filter.py +188 -0
  143. careamics/dataset_ng/patch_filter/mean_std_filter.py +218 -0
  144. careamics/dataset_ng/patch_filter/patch_filter_protocol.py +50 -0
  145. careamics/dataset_ng/patch_filter/shannon_filter.py +188 -0
  146. careamics/dataset_ng/patching_strategies/__init__.py +26 -0
  147. careamics/dataset_ng/patching_strategies/patching_strategy_factory.py +50 -0
  148. careamics/dataset_ng/patching_strategies/patching_strategy_protocol.py +161 -0
  149. careamics/dataset_ng/patching_strategies/random_patching.py +393 -0
  150. careamics/dataset_ng/patching_strategies/sequential_patching.py +99 -0
  151. careamics/dataset_ng/patching_strategies/tiling_strategy.py +207 -0
  152. careamics/dataset_ng/patching_strategies/whole_sample.py +61 -0
  153. careamics/file_io/__init__.py +15 -0
  154. careamics/file_io/read/__init__.py +11 -0
  155. careamics/file_io/read/get_func.py +57 -0
  156. careamics/file_io/read/tiff.py +58 -0
  157. careamics/file_io/write/__init__.py +15 -0
  158. careamics/file_io/write/get_func.py +63 -0
  159. careamics/file_io/write/tiff.py +40 -0
  160. careamics/lightning/__init__.py +32 -0
  161. careamics/lightning/callbacks/__init__.py +13 -0
  162. careamics/lightning/callbacks/data_stats_callback.py +33 -0
  163. careamics/lightning/callbacks/hyperparameters_callback.py +49 -0
  164. careamics/lightning/callbacks/prediction_writer_callback/__init__.py +20 -0
  165. careamics/lightning/callbacks/prediction_writer_callback/file_path_utils.py +56 -0
  166. careamics/lightning/callbacks/prediction_writer_callback/prediction_writer_callback.py +234 -0
  167. careamics/lightning/callbacks/prediction_writer_callback/write_strategy.py +399 -0
  168. careamics/lightning/callbacks/prediction_writer_callback/write_strategy_factory.py +215 -0
  169. careamics/lightning/callbacks/progress_bar_callback.py +90 -0
  170. careamics/lightning/dataset_ng/__init__.py +1 -0
  171. careamics/lightning/dataset_ng/callbacks/__init__.py +1 -0
  172. careamics/lightning/dataset_ng/callbacks/prediction_writer/__init__.py +29 -0
  173. careamics/lightning/dataset_ng/callbacks/prediction_writer/cached_tiles_strategy.py +164 -0
  174. careamics/lightning/dataset_ng/callbacks/prediction_writer/file_path_utils.py +33 -0
  175. careamics/lightning/dataset_ng/callbacks/prediction_writer/prediction_writer_callback.py +219 -0
  176. careamics/lightning/dataset_ng/callbacks/prediction_writer/write_image_strategy.py +91 -0
  177. careamics/lightning/dataset_ng/callbacks/prediction_writer/write_strategy.py +27 -0
  178. careamics/lightning/dataset_ng/callbacks/prediction_writer/write_strategy_factory.py +214 -0
  179. careamics/lightning/dataset_ng/callbacks/prediction_writer/write_tiles_zarr_strategy.py +375 -0
  180. careamics/lightning/dataset_ng/data_module.py +529 -0
  181. careamics/lightning/dataset_ng/data_module_utils.py +395 -0
  182. careamics/lightning/dataset_ng/lightning_modules/__init__.py +9 -0
  183. careamics/lightning/dataset_ng/lightning_modules/care_module.py +97 -0
  184. careamics/lightning/dataset_ng/lightning_modules/n2v_module.py +106 -0
  185. careamics/lightning/dataset_ng/lightning_modules/unet_module.py +221 -0
  186. careamics/lightning/dataset_ng/prediction/__init__.py +16 -0
  187. careamics/lightning/dataset_ng/prediction/convert_prediction.py +198 -0
  188. careamics/lightning/dataset_ng/prediction/stitch_prediction.py +171 -0
  189. careamics/lightning/lightning_module.py +914 -0
  190. careamics/lightning/microsplit_data_module.py +632 -0
  191. careamics/lightning/predict_data_module.py +341 -0
  192. careamics/lightning/train_data_module.py +666 -0
  193. careamics/losses/__init__.py +21 -0
  194. careamics/losses/fcn/__init__.py +1 -0
  195. careamics/losses/fcn/losses.py +125 -0
  196. careamics/losses/loss_factory.py +80 -0
  197. careamics/losses/lvae/__init__.py +1 -0
  198. careamics/losses/lvae/loss_utils.py +83 -0
  199. careamics/losses/lvae/losses.py +589 -0
  200. careamics/lvae_training/__init__.py +0 -0
  201. careamics/lvae_training/calibration.py +191 -0
  202. careamics/lvae_training/dataset/__init__.py +20 -0
  203. careamics/lvae_training/dataset/config.py +135 -0
  204. careamics/lvae_training/dataset/lc_dataset.py +274 -0
  205. careamics/lvae_training/dataset/ms_dataset_ref.py +1067 -0
  206. careamics/lvae_training/dataset/multich_dataset.py +1121 -0
  207. careamics/lvae_training/dataset/multicrop_dset.py +196 -0
  208. careamics/lvae_training/dataset/multifile_dataset.py +335 -0
  209. careamics/lvae_training/dataset/types.py +32 -0
  210. careamics/lvae_training/dataset/utils/__init__.py +0 -0
  211. careamics/lvae_training/dataset/utils/data_utils.py +114 -0
  212. careamics/lvae_training/dataset/utils/empty_patch_fetcher.py +65 -0
  213. careamics/lvae_training/dataset/utils/index_manager.py +491 -0
  214. careamics/lvae_training/dataset/utils/index_switcher.py +165 -0
  215. careamics/lvae_training/eval_utils.py +987 -0
  216. careamics/lvae_training/get_config.py +84 -0
  217. careamics/lvae_training/lightning_module.py +701 -0
  218. careamics/lvae_training/metrics.py +214 -0
  219. careamics/lvae_training/train_lvae.py +342 -0
  220. careamics/lvae_training/train_utils.py +121 -0
  221. careamics/model_io/__init__.py +7 -0
  222. careamics/model_io/bioimage/__init__.py +11 -0
  223. careamics/model_io/bioimage/_readme_factory.py +113 -0
  224. careamics/model_io/bioimage/bioimage_utils.py +56 -0
  225. careamics/model_io/bioimage/cover_factory.py +171 -0
  226. careamics/model_io/bioimage/model_description.py +341 -0
  227. careamics/model_io/bmz_io.py +251 -0
  228. careamics/model_io/model_io_utils.py +95 -0
  229. careamics/models/__init__.py +5 -0
  230. careamics/models/activation.py +40 -0
  231. careamics/models/layers.py +495 -0
  232. careamics/models/lvae/__init__.py +3 -0
  233. careamics/models/lvae/layers.py +1371 -0
  234. careamics/models/lvae/likelihoods.py +394 -0
  235. careamics/models/lvae/lvae.py +848 -0
  236. careamics/models/lvae/noise_models.py +738 -0
  237. careamics/models/lvae/stochastic.py +394 -0
  238. careamics/models/lvae/utils.py +404 -0
  239. careamics/models/model_factory.py +54 -0
  240. careamics/models/unet.py +449 -0
  241. careamics/nm_training_placeholder.py +203 -0
  242. careamics/prediction_utils/__init__.py +21 -0
  243. careamics/prediction_utils/lvae_prediction.py +158 -0
  244. careamics/prediction_utils/lvae_tiling_manager.py +362 -0
  245. careamics/prediction_utils/prediction_outputs.py +238 -0
  246. careamics/prediction_utils/stitch_prediction.py +193 -0
  247. careamics/py.typed +5 -0
  248. careamics/transforms/__init__.py +22 -0
  249. careamics/transforms/compose.py +173 -0
  250. careamics/transforms/n2v_manipulate.py +150 -0
  251. careamics/transforms/n2v_manipulate_torch.py +149 -0
  252. careamics/transforms/normalize.py +374 -0
  253. careamics/transforms/pixel_manipulation.py +406 -0
  254. careamics/transforms/pixel_manipulation_torch.py +388 -0
  255. careamics/transforms/struct_mask_parameters.py +20 -0
  256. careamics/transforms/transform.py +24 -0
  257. careamics/transforms/tta.py +88 -0
  258. careamics/transforms/xy_flip.py +131 -0
  259. careamics/transforms/xy_random_rotate90.py +108 -0
  260. careamics/utils/__init__.py +19 -0
  261. careamics/utils/autocorrelation.py +40 -0
  262. careamics/utils/base_enum.py +60 -0
  263. careamics/utils/context.py +67 -0
  264. careamics/utils/deprecation.py +63 -0
  265. careamics/utils/lightning_utils.py +71 -0
  266. careamics/utils/logging.py +323 -0
  267. careamics/utils/metrics.py +394 -0
  268. careamics/utils/path_utils.py +26 -0
  269. careamics/utils/plotting.py +76 -0
  270. careamics/utils/ram.py +15 -0
  271. careamics/utils/receptive_field.py +108 -0
  272. careamics/utils/serializers.py +62 -0
  273. careamics/utils/torch_utils.py +150 -0
  274. careamics/utils/version.py +38 -0
  275. careamics-0.0.19.dist-info/METADATA +80 -0
  276. careamics-0.0.19.dist-info/RECORD +279 -0
  277. careamics-0.0.19.dist-info/WHEEL +4 -0
  278. careamics-0.0.19.dist-info/entry_points.txt +2 -0
  279. careamics-0.0.19.dist-info/licenses/LICENSE +28 -0
@@ -0,0 +1,70 @@
1
+ from collections.abc import Sequence
2
+ from typing import Any, Protocol
3
+
4
+ from typing_extensions import ParamSpec
5
+
6
+ from careamics.utils import BaseEnum
7
+
8
+ from ..image_stack import GenericImageStack
9
+
10
+ P = ParamSpec("P")
11
+
12
+
13
+ class SupportedDataDev(str, BaseEnum):
14
+ ZARR = "zarr"
15
+
16
+
17
+ class ImageStackLoader(Protocol[P, GenericImageStack]):
18
+ """
19
+ Protocol to define how `ImageStacks` should be loaded.
20
+
21
+ An `ImageStackLoader` is a callable that must take the `source` of the data as the
22
+ first argument, and the data `axes` as the second argument.
23
+
24
+ Additional `*args` and `**kwargs` are allowed, but they should only be used to
25
+ determine _how_ the data is loaded, not _what_ data is loaded. The `source`
26
+ argument has to wholly determine _what_ data is loaded, this is because,
27
+ downstream, both an input-source and a target-source have to be specified but they
28
+ will share `*args` and `**kwargs`.
29
+
30
+ An `ImageStackLoader` must return a sequence of the `ImageStack` class. This could
31
+ be a sequence of one of the existing concrete implementations, such as
32
+ `ZarrImageStack`, or a custom user defined `ImageStack`.
33
+
34
+ Example
35
+ -------
36
+ The following example demonstrates how an `ImageStackLoader` could be defined
37
+ for loading non-OME Zarr images. Returning a list of `ZarrImageStack` instances.
38
+
39
+ >>> from typing import TypedDict
40
+
41
+ >>> from zarr.storage import FsspecStore
42
+
43
+ >>> from careamics.config import DataConfig
44
+ >>> from careamics.dataset_ng.image_stack import ZarrImageStack
45
+
46
+ >>> # Define a zarr source
47
+ >>> # It encompasses multiple arguments that determine what data will be loaded
48
+ >>> class ZarrSource(TypedDict):
49
+ ... store: FsspecStore
50
+ ... data_paths: Sequence[str]
51
+
52
+ >>> def custom_image_stack_loader(
53
+ ... source: ZarrSource, axes: str, *args, **kwargs
54
+ ... ) -> list[ZarrImageStack]:
55
+ ... image_stacks = [
56
+ ... ZarrImageStack(store=source["store"], data_path=data_path, axes=axes)
57
+ ... for data_path in source["data_paths"]
58
+ ... ]
59
+ ... return image_stacks
60
+
61
+ TODO: show example use in the `CAREamicsDataset`
62
+
63
+ The example above defines a `ZarrSource` dict because to determine _which_ ZARR
64
+ images will be loaded both a ZARR store and the internal data paths need to be
65
+ specified.
66
+ """
67
+
68
+ def __call__(
69
+ self, source: Any, axes: str, *args: P.args, **kwargs: P.kwargs
70
+ ) -> Sequence[GenericImageStack]: ...
@@ -0,0 +1,273 @@
1
+ from collections.abc import Sequence
2
+ from pathlib import Path
3
+ from typing import TYPE_CHECKING, Any, Literal
4
+
5
+ import zarr
6
+ from numpy.typing import NDArray
7
+ from zarr.storage import StorePath
8
+
9
+ from careamics.config.validators import check_czi_axes_validity
10
+ from careamics.file_io import ReadFunc
11
+
12
+ from ..image_stack import (
13
+ FileImageStack,
14
+ InMemoryImageStack,
15
+ ZarrImageStack,
16
+ )
17
+ from ..image_stack.czi_image_stack import CziImageStack
18
+ from .zarr_utils import collect_arrays, decipher_zarr_uri, is_ome_zarr, is_valid_uri
19
+
20
+ if TYPE_CHECKING:
21
+ from careamics.file_io.read import ReadFunc
22
+
23
+
24
+ def load_arrays(source: Sequence[NDArray[Any]], axes: str) -> list[InMemoryImageStack]:
25
+ """
26
+ Load image stacks from a sequence of numpy arrays.
27
+
28
+ Parameters
29
+ ----------
30
+ source: sequence of numpy.ndarray
31
+ The source arrays of the data.
32
+ axes: str
33
+ The original axes of the data, must be a subset of "STCZYX".
34
+
35
+ Returns
36
+ -------
37
+ list[InMemoryImageStack]
38
+ """
39
+ return [InMemoryImageStack.from_array(data=array, axes=axes) for array in source]
40
+
41
+
42
+ # TIFF case
43
+ def load_tiffs(source: Sequence[Path], axes: str) -> list[InMemoryImageStack]:
44
+ """
45
+ Load image stacks from a sequence of TIFF files.
46
+
47
+ Parameters
48
+ ----------
49
+ source: sequence of Path
50
+ The source files for the data.
51
+ axes: str
52
+ The original axes of the data, must be a subset of "STCZYX".
53
+
54
+ Returns
55
+ -------
56
+ list[InMemoryImageStack]
57
+ """
58
+ return [InMemoryImageStack.from_tiff(path=path, axes=axes) for path in source]
59
+
60
+
61
+ # TODO: better name
62
+ # iter Tiff
63
+ def load_iter_tiff(source: Sequence[Path], axes: str) -> list[FileImageStack]:
64
+ # TODO: better docs
65
+ """
66
+ Load image stacks from a sequence of TIFF files.
67
+
68
+ Parameters
69
+ ----------
70
+ source: sequence of Path
71
+ The source files for the data.
72
+ axes: str
73
+ The original axes of the data, must be a subset of "STCZYX".
74
+
75
+ Returns
76
+ -------
77
+ list[FileImageStack]
78
+ """
79
+ return [FileImageStack.from_tiff(path=path, axes=axes) for path in source]
80
+
81
+
82
+ # Custom file type case (loaded into memory)
83
+ def load_custom_file(
84
+ source: Sequence[Path],
85
+ axes: str,
86
+ *,
87
+ read_func: ReadFunc,
88
+ read_kwargs: dict[str, Any],
89
+ ) -> list[InMemoryImageStack]:
90
+ """
91
+ Load image stacks from a sequence of files of a custom type.
92
+
93
+ Parameters
94
+ ----------
95
+ source: sequence of Path
96
+ The source files for the data.
97
+ axes: str
98
+ The original axes of the data, must be a subset of "STCZYX".
99
+ read_func : ReadFunc
100
+ A function to read the custom file type, see the `ReadFunc` protocol.
101
+ read_kwargs : dict of {str: Any}
102
+ Kwargs that will be passed to the custom `read_func`.
103
+
104
+ Returns
105
+ -------
106
+ list[InMemoryImageStack]
107
+ """
108
+ # TODO: lazy loading custom files
109
+ return [
110
+ InMemoryImageStack.from_custom_file_type(
111
+ path=path,
112
+ axes=axes,
113
+ read_func=read_func,
114
+ **read_kwargs,
115
+ )
116
+ for path in source
117
+ ]
118
+
119
+
120
+ def load_zarrs(
121
+ source: Sequence[str | Path | StorePath],
122
+ axes: str,
123
+ ) -> list[ZarrImageStack]:
124
+ """Create a list of ZarrImageStack from a sequence of zarr file paths or URIs.
125
+
126
+ File paths must point to a zarr store (ending with .zarr) and URIs must be in the
127
+ format "file://path/to/zarr_store.zarr/group/path/array_name".
128
+
129
+ If the zarr file is an OME-Zarr, the specified multiscale level will be used. Note
130
+ that OME-Zarrs are only supported when providing a path to the zarr store, not when
131
+ using a file URI. One can, however, provide a file URI to the specific resolution
132
+ array within the OME-Zarr.
133
+
134
+ Parameters
135
+ ----------
136
+ source : sequence of str or Path
137
+ The source zarr file paths or URIs.
138
+ axes : str
139
+ The original axes of the data, must be a subset of "STCZYX".
140
+
141
+ Returns
142
+ -------
143
+ list of ZarrImageStack
144
+ A list of ZarrImageStack created from the sources.
145
+ """
146
+
147
+ image_stacks: list[ZarrImageStack] = []
148
+
149
+ for data_source in source:
150
+ data_str = str(data_source)
151
+
152
+ # either a path to a zarr file or a uri "file://path/to/zarr/array_path"
153
+ if data_str.endswith(".zarr"):
154
+ zarr_group = zarr.open_group(data_str, mode="r")
155
+
156
+ # test if ome-zarr (minimum assumption of multiscales)
157
+ if is_ome_zarr(zarr_group):
158
+ # TODO placeholder for handling OME-Zarr
159
+ # - Need to potentially select multiscale level
160
+ # - Extract axes and compare with provided ones
161
+ raise NotImplementedError(
162
+ "OME-Zarr support is not yet implemented when providing a "
163
+ "path to the zarr store. Please provide a file URI to the "
164
+ "specific array within the OME-Zarr."
165
+ )
166
+ else:
167
+ # collect all arrays
168
+ array_paths = collect_arrays(zarr_group)
169
+
170
+ # sort names
171
+ array_paths.sort()
172
+
173
+ # instantiate image stacks
174
+ for array_path in array_paths:
175
+ image_stacks.append(
176
+ ZarrImageStack(group=zarr_group, data_path=array_path, axes=axes)
177
+ )
178
+
179
+ elif is_valid_uri(data_str):
180
+ # decipher the uri and open the group
181
+ store_path, parent_path, name = decipher_zarr_uri(data_str)
182
+
183
+ zarr_group = zarr.open_group(store_path, path=parent_path, mode="r")
184
+ content = zarr_group[name]
185
+
186
+ # assert if group or array
187
+ if isinstance(content, zarr.Group):
188
+ array_paths = collect_arrays(content)
189
+
190
+ # sort the names
191
+ array_paths.sort()
192
+
193
+ for array_path in array_paths:
194
+ image_stacks.append(
195
+ ZarrImageStack(group=content, data_path=array_path, axes=axes)
196
+ )
197
+ else:
198
+ if not isinstance(content, zarr.Array):
199
+ raise TypeError(
200
+ f"Content at '{data_str}' is neither a zarr.Group nor "
201
+ f"a zarr.Array."
202
+ )
203
+
204
+ # create image stack from a single array
205
+ image_stacks.append(
206
+ ZarrImageStack(
207
+ group=zarr_group,
208
+ data_path=name,
209
+ axes=axes,
210
+ )
211
+ )
212
+
213
+ else:
214
+ raise ValueError(
215
+ f"Source '{data_source}' is neither a zarr file nor a file URI."
216
+ )
217
+
218
+ return image_stacks
219
+
220
+
221
+ def load_czis(
222
+ source: Sequence[Path],
223
+ axes: str,
224
+ ) -> list[CziImageStack]:
225
+ """
226
+ Load CZI image stacks from a sequence of CZI files paths.
227
+
228
+ If the CZI files contain multiple scenes, one image stack will be created for
229
+ each scene.
230
+
231
+ Axes should be in the format "SC(Z/T)YX", where Z or T are optional, and S and C
232
+ can be singleton dimensions, but must be provided.
233
+
234
+ Parameters
235
+ ----------
236
+ source: sequence of Path
237
+ The source files for the data.
238
+ axes: str
239
+ Specifies which axes of the data to use and how.
240
+ If this string ends with `"ZYX"` or `"TYX"`, the data will consist of 3-D
241
+ patches, using `Z` or `T` as third dimension, respectively.
242
+ If the string does not end with "ZYX", the data will consist of 2-D patches.
243
+
244
+ Returns
245
+ -------
246
+ list[CziImageStack]
247
+
248
+ Raises
249
+ ------
250
+ ValueError
251
+ If the provided axes are not valid.
252
+ """
253
+ if check_czi_axes_validity(axes) is False:
254
+ raise ValueError(
255
+ f"Provided axes '{axes}' are not valid. Axes must be in the `SC(Z/T)YX` "
256
+ f"format, where Z or T are optional, and S and C can be singleton "
257
+ f"dimensions, but must be provided."
258
+ )
259
+
260
+ depth_axis: Literal["none", "Z", "T"] = "none"
261
+ if axes.endswith("TYX"):
262
+ depth_axis = "T"
263
+ elif axes.endswith("ZYX"):
264
+ depth_axis = "Z"
265
+
266
+ image_stacks: list[CziImageStack] = []
267
+ for path in source:
268
+ scene_rectangles = CziImageStack.get_bounding_rectangles(path)
269
+ image_stacks.extend(
270
+ CziImageStack(path, scene=scene, depth_axis=depth_axis)
271
+ for scene in scene_rectangles.keys()
272
+ )
273
+ return image_stacks
@@ -0,0 +1,130 @@
1
+ import warnings
2
+ from pathlib import Path
3
+ from urllib.parse import urlparse
4
+
5
+ import zarr
6
+
7
+ INPUT = str | Path
8
+
9
+
10
+ def is_valid_uri(path: str | Path) -> bool:
11
+ """
12
+ Check if a path is a valid URI.
13
+
14
+ Parameters
15
+ ----------
16
+ path : str | Path
17
+ The path to check.
18
+
19
+ Returns
20
+ -------
21
+ bool
22
+ True if the path is valid URI, False otherwise.
23
+ """
24
+ parsed = urlparse(str(path))
25
+
26
+ valid_schemes = {"file", "s3", "gs", "az", "https", "http", "zip"}
27
+
28
+ if parsed.scheme and parsed.scheme.lower() in valid_schemes:
29
+ return True
30
+
31
+ return False
32
+
33
+
34
+ def collect_arrays(zarr_group: zarr.Group) -> list[str]:
35
+ """
36
+ Collect all arrays in a Zarr group into a list.
37
+
38
+ Only run on the first level of the group.
39
+
40
+ Parameters
41
+ ----------
42
+ zarr_group : zarr.Group
43
+ The Zarr group to collect arrays from.
44
+
45
+ Returns
46
+ -------
47
+ listof str
48
+ A list of Zarr arrays contained in the group as relative path to the group.
49
+ """
50
+ arrays: list[str] = []
51
+
52
+ for name in zarr_group.array_keys():
53
+ if isinstance(zarr_group[name], zarr.Array):
54
+ arrays.append(name)
55
+
56
+ if arrays == []:
57
+ warnings.warn(
58
+ f"No arrays found in zarr group at '{zarr_group.path}'.",
59
+ UserWarning,
60
+ stacklevel=2,
61
+ )
62
+
63
+ return arrays
64
+
65
+
66
+ def decipher_zarr_uri(source: str) -> tuple[str, str, str]:
67
+ """Extract the zarr store path, group path and array path from a zarr source string.
68
+
69
+ The input string is expected to be in the format:
70
+ \"file://path/to/zarr_store.zarr/group/path/array_name\"
71
+
72
+ Note that the root folder of the zarr store must end with ".zarr".
73
+
74
+ Parameters
75
+ ----------
76
+ source : str
77
+ The zarr source string.
78
+
79
+ Returns
80
+ -------
81
+ str
82
+ The path to the zarr store.
83
+ str
84
+ The parent group within the zarr store, if it is not the root, else "".
85
+ str
86
+ The group or array name the source is pointing to.
87
+
88
+ Raises
89
+ ------
90
+ ValueError
91
+ If the source string does not start with "file://".
92
+ ValueError
93
+ If the source string does not contain a ".zarr" file extension.
94
+ """
95
+ key = "file://"
96
+
97
+ if source[: len(key)] != key:
98
+ raise ValueError(f"Remote file not supported: {source}")
99
+
100
+ if ".zarr" not in source:
101
+ raise ValueError(f"No .zarr file extension found in source: {source}")
102
+
103
+ _source = source[len(key) :]
104
+ groups = _source.split("/")
105
+
106
+ # find .zarr entry
107
+ zarr_index = next((i for i, p in enumerate(groups) if p.endswith(".zarr")))
108
+
109
+ path_to_zarr = groups[: zarr_index + 1]
110
+ parent_path = groups[zarr_index + 1 : -1]
111
+ content_path = groups[-1]
112
+
113
+ return "/".join(path_to_zarr), "/".join(parent_path), content_path
114
+
115
+
116
+ # TODO use yaozarrs models to validate OME-Zarr structure
117
+ def is_ome_zarr(zarr_group: zarr.Group) -> bool:
118
+ """Check if a Zarr group is an OME-Zarr.
119
+
120
+ Parameters
121
+ ----------
122
+ zarr_group : zarr.Group
123
+ The Zarr group to check.
124
+
125
+ Returns
126
+ -------
127
+ bool
128
+ True if the Zarr group is an OME-Zarr, False otherwise.
129
+ """
130
+ return False
@@ -0,0 +1,175 @@
1
+ """
2
+ A module for utility functions that adapts the new dataset outputs to work with previous
3
+ code until it is updated.
4
+ """
5
+
6
+ from collections.abc import Sequence
7
+ from typing import cast
8
+
9
+ import numpy as np
10
+ from numpy.typing import NDArray
11
+
12
+ from careamics.config.data.tile_information import TileInformation
13
+ from careamics.utils.deprecation import deprecated
14
+
15
+ from .dataset import ImageRegionData
16
+ from .patching_strategies import TileSpecs
17
+
18
+
19
+ @deprecated(
20
+ "use careamics.lightning.dataset_ng.prediction functions instead for stitching and"
21
+ " combining predictions."
22
+ )
23
+ def imageregions_to_tileinfos(
24
+ image_regions: Sequence[ImageRegionData],
25
+ ) -> list[tuple[NDArray, list[TileInformation]]]:
26
+ """
27
+ Converts a series of `TileSpecs` dictionaries to `TileInformation` pydantic class.
28
+
29
+ Parameters
30
+ ----------
31
+ image_regions : sequence of ImageRegionData
32
+ A list of ImageRegionData, it must have an instance of `TileSpecs` as it's
33
+ `region_data` field.
34
+
35
+ Returns
36
+ -------
37
+ list of TileInformation
38
+ The converted tile information.
39
+ """
40
+
41
+ tile_infos: list[TileInformation] = []
42
+
43
+ data = [image_region.data for image_region in image_regions]
44
+ tile_specs = [image_region.region_spec for image_region in image_regions]
45
+
46
+ data_indices: NDArray[np.int_] = np.array(
47
+ [tile_spec["data_idx"] for tile_spec in tile_specs], dtype=int
48
+ )
49
+ unique_data_indices = np.unique(data_indices)
50
+ # data_idx denotes which image stack a patch belongs to
51
+ # separate TileSpecs by image_stack
52
+ for data_idx in unique_data_indices:
53
+ # collect all ImageRegions
54
+ data_image_regions: list[ImageRegionData] = [
55
+ image_region
56
+ for image_region in image_regions
57
+ if image_region.region_spec["data_idx"] == data_idx
58
+ ]
59
+
60
+ # --- find last indices
61
+ # make sure tiles belonging to the same sample are together
62
+ data_image_regions.sort(
63
+ key=lambda image_region: image_region.region_spec["sample_idx"]
64
+ )
65
+ sample_indices = np.array(
66
+ [
67
+ image_region.region_spec["sample_idx"]
68
+ for image_region in data_image_regions
69
+ ]
70
+ )
71
+ # reverse array so indices returned are at far edge
72
+ _, unique_indices = np.unique(sample_indices[::-1], return_index=True)
73
+ # un reverse indices
74
+ last_indices = len(sample_indices) - 1 - unique_indices
75
+
76
+ # convert each ImageRegionData to tile_info
77
+ for i, image_region in enumerate(data_image_regions):
78
+ last_tile = i in last_indices
79
+ tile_info = _imageregion_to_tileinfo(image_region, last_tile)
80
+ tile_infos.append(tile_info)
81
+
82
+ return [
83
+ (data, [tile_info]) for data, tile_info in zip(data, tile_infos, strict=False)
84
+ ]
85
+
86
+
87
+ def _imageregion_to_tileinfo(
88
+ image_region: ImageRegionData, last_tile: bool
89
+ ) -> TileInformation:
90
+ """
91
+ Convert a single `ImageRegionData` instance to a `TileInformation` instance. Whether
92
+ it is the last tile in a sequence needs to be supplied.
93
+
94
+ Parameters
95
+ ----------
96
+ image_region : ImageRegionData
97
+ An instance of `ImageRegionData`, it must have an instance of `TileSpecs` as
98
+ it's `region_data` field.
99
+ last_tile : bool
100
+ Whether a tile is the last tile in a sequence, for stitching.
101
+
102
+ Returns
103
+ -------
104
+ TileInformation
105
+ A tile information object.
106
+
107
+ Raises
108
+ ------
109
+ KeyError
110
+ If `image_region.region_spec` does not contain the keys: {'crop_coords',
111
+ 'crop_size', 'stitch_coords'}.
112
+ """
113
+ patch_spec = image_region.region_spec
114
+ data_shape = image_region.data_shape
115
+
116
+ # TODO: In python 3.11 and greater, NamedTuples can inherit from Generic
117
+ # so we could do image_region: ImageRegionData[TileSpecs]
118
+ # and not have to do this check here + cast
119
+ # make sure image_region.region_spec is TileSpec
120
+ if (
121
+ ("crop_coords" not in patch_spec)
122
+ or ("crop_size" not in patch_spec)
123
+ or ("stitch_coords" not in patch_spec)
124
+ ):
125
+ raise KeyError(
126
+ "Could not find all keys: {'crop_coords', 'crop_size', 'stitch_coords'} in "
127
+ "`image_region.region_spec`."
128
+ )
129
+ tile_spec = cast(TileSpecs, patch_spec) # ugly cast for mypy
130
+ return _tilespec_to_tileinfo(tile_spec, data_shape, last_tile)
131
+
132
+
133
+ def _tilespec_to_tileinfo(
134
+ tile_spec: TileSpecs, data_shape: Sequence[int], last_tile: bool
135
+ ) -> TileInformation:
136
+ """
137
+ Convert a single `TileSpec` to a `TileInformation`. Whether it is the last tile
138
+ needs to be supplied.
139
+
140
+ Parameters
141
+ ----------
142
+ tile_spec : TileSpecs
143
+ A tile spec dictionary.
144
+ data_shape : sequence of int
145
+ The original shape of the data the tile came from, labeling the dimensions of
146
+ axes SC(Z)YX.
147
+ last_tile : bool
148
+ Whether a tile is the last tile in a sequence, for stitching.
149
+
150
+ Returns
151
+ -------
152
+ TileInformation
153
+ A tile information object.
154
+ """
155
+ overlap_crop_coords = tuple(
156
+ (
157
+ tile_spec["crop_coords"][i],
158
+ tile_spec["crop_coords"][i] + tile_spec["crop_size"][i],
159
+ )
160
+ for i in range(len(tile_spec["crop_coords"]))
161
+ )
162
+ stitch_coords = tuple(
163
+ (
164
+ tile_spec["stitch_coords"][i],
165
+ tile_spec["stitch_coords"][i] + tile_spec["crop_size"][i],
166
+ )
167
+ for i in range(len(tile_spec["crop_coords"]))
168
+ )
169
+ return TileInformation(
170
+ array_shape=tuple(data_shape[1:]), # remove sample dimension
171
+ last_tile=last_tile,
172
+ overlap_crop_coords=overlap_crop_coords,
173
+ stitch_coords=stitch_coords,
174
+ sample_id=tile_spec["sample_idx"],
175
+ )