|
7 | 7 |
|
8 | 8 | from anndata import AnnData, read_text |
9 | 9 | from h5py import File |
| 10 | +from ome_types import from_tiff |
| 11 | +from ome_types.model import Pixels, UnitsLength |
| 12 | +from spatialdata._logging import logger |
10 | 13 |
|
11 | 14 | from spatialdata_io.readers._utils._read_10x_h5 import _read_10x_h5 |
12 | 15 |
|
@@ -75,3 +78,48 @@ def _initialize_raster_models_kwargs( |
75 | 78 | if "scale_factors" not in labels_models_kwargs: |
76 | 79 | labels_models_kwargs["scale_factors"] = [2, 2, 2, 2] |
77 | 80 | return image_models_kwargs, labels_models_kwargs |
| 81 | + |
| 82 | + |
| 83 | +def calc_scale_factors(lower_scale_limit: float, min_size: int = 1000, default_scale_factor: int = 2) -> list[int]: |
| 84 | + """Calculate scale factors based on image size to get lowest resolution under min_size pixels.""" |
| 85 | + # get lowest dimension, ignoring channels |
| 86 | + scale_factor: int = default_scale_factor |
| 87 | + scale_factors = [scale_factor] |
| 88 | + lower_scale_limit /= scale_factor |
| 89 | + while lower_scale_limit >= min_size: |
| 90 | + # scale_factors are cumulative, so we don't need to do e.g. scale_factor *= 2 |
| 91 | + scale_factors.append(scale_factor) |
| 92 | + lower_scale_limit /= scale_factor |
| 93 | + return scale_factors |
| 94 | + |
| 95 | + |
| 96 | +def parse_channels(path: Path) -> list[str]: |
| 97 | + """Parse channel names from an OME-TIFF file.""" |
| 98 | + images = from_tiff(path).images |
| 99 | + if len(images) > 1: |
| 100 | + logger.warning("Found multiple images in OME-TIFF file. Only the first one will be used.") |
| 101 | + channels = images[0].pixels.channels |
| 102 | + logger.debug(channels) |
| 103 | + names = [c.name for c in channels if c.name is not None] |
| 104 | + return names |
| 105 | + |
| 106 | + |
| 107 | +def parse_physical_size(path: Path | None = None, ome_pixels: Pixels | None = None) -> float: |
| 108 | + """Parse physical size from OME-TIFF to micrometer.""" |
| 109 | + pixels = ome_pixels or from_tiff(path).images[0].pixels |
| 110 | + logger.debug(pixels) |
| 111 | + if pixels.physical_size_x_unit != pixels.physical_size_y_unit: |
| 112 | + logger.error("Physical units for x and y dimensions are not the same.") |
| 113 | + raise NotImplementedError |
| 114 | + if pixels.physical_size_x != pixels.physical_size_y: |
| 115 | + logger.error("Physical sizes for x and y dimensions are not the same.") |
| 116 | + raise NotImplementedError |
| 117 | + # convert to micrometer if needed |
| 118 | + if pixels.physical_size_x_unit == UnitsLength.NANOMETER: |
| 119 | + physical_size = pixels.physical_size_x / 1000 |
| 120 | + elif pixels.physical_size_x_unit == UnitsLength.MICROMETER: |
| 121 | + physical_size = pixels.physical_size_x |
| 122 | + else: |
| 123 | + logger.error(f"Physical unit not recognized: '{pixels.physical_size_x_unit}'.") |
| 124 | + raise NotImplementedError |
| 125 | + return float(physical_size) |
0 commit comments