From 8ff52f5af5e06e3e94e796583bd9732e5f20a553 Mon Sep 17 00:00:00 2001 From: "w.pomp" Date: Mon, 26 Jan 2026 17:03:27 +0100 Subject: [PATCH] - main_channel and default_transform arguments for Imread.with_transform --- ndbioimage/__init__.py | 9 ++++++++- ndbioimage/transforms.py | 31 +++++++++++++++++++------------ pyproject.toml | 2 +- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ndbioimage/__init__.py b/ndbioimage/__init__.py index e77f428..9a5a27f 100755 --- a/ndbioimage/__init__.py +++ b/ndbioimage/__init__.py @@ -1253,6 +1253,8 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC): drift: bool = False, file: Path | str = None, bead_files: Sequence[Path | str] = (), + main_channel: int = None, + default_transform: Sequence[float] = None, ) -> View: """returns a view where channels and/or frames are registered with an affine transformation channels: True/False register channels using bead_files @@ -1260,6 +1262,11 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC): file: load registration from file with name file, default: transform.yml in self.path.parent bead_files: files used to register channels, default: files in self.path.parent, with names starting with 'beads' + main channel: which channel to transform with default_transform + default_transform: parameters of the default transform: [a, b, c, d, e, f] where the affine transform matrix is + | a b e | + | c d f | + | 0 0 1 | """ view = self.view() if file is None: @@ -1278,7 +1285,7 @@ class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC): try: view.transform = Transforms.from_file(file, T=drift) except Exception: # noqa - view.transform = Transforms().with_beads(view.cyllens, bead_files) + view.transform = Transforms().with_beads(view.cyllens, bead_files, main_channel, default_transform) if drift: view.transform = view.transform.with_drift(view) view.transform.save(file.with_suffix(".yml")) diff --git a/ndbioimage/transforms.py b/ndbioimage/transforms.py index 19a4a24..46b2a3d 100644 --- a/ndbioimage/transforms.py +++ b/ndbioimage/transforms.py @@ -147,9 +147,11 @@ class Transforms(dict): else: raise TypeError("Not a pandas DataFrame or Series.") - def with_beads(self, cyllens, bead_files): + def with_beads(self, cyllens, bead_files, main_channel=None, default_transform=None): assert len(bead_files) > 0, "At least one file is needed to calculate the registration." - transforms = [self.calculate_channel_transforms(file, cyllens) for file in bead_files] + transforms = [ + self.calculate_channel_transforms(file, cyllens, main_channel, default_transform) for file in bead_files + ] for key in {key for transform in transforms for key in transform.keys()}: new_transforms = [transform[key] for transform in transforms if key in transform] if len(new_transforms) == 1: @@ -191,7 +193,7 @@ class Transforms(dict): return checked_files @staticmethod - def calculate_channel_transforms(bead_file, cyllens): + def calculate_channel_transforms(bead_file, cyllens, main_channel=None, default_transform=None): """When no channel is not transformed by a cylindrical lens, assume that the image is scaled by a factor 1.162 in the horizontal direction""" from . import Imread @@ -204,25 +206,30 @@ class Transforms(dict): untransformed = [c for c in range(im.shape["c"]) if cyllens[im.detector[c]].lower() == "none"] good_and_untrans = sorted(set(goodch) & set(untransformed)) - if good_and_untrans: - masterch = good_and_untrans[0] - else: - masterch = goodch[0] + if main_channel is None: + if good_and_untrans: + main_channel = good_and_untrans[0] + else: + main_channel = goodch[0] transform = Transform() if not good_and_untrans: matrix = transform.matrix - matrix[0, 0] = 0.86 + if default_transform is None: + matrix[0, 0] = 0.86 + else: + for i, t in zip(([0, 0], [0, 1], [1, 0], [1, 1], [0, 2], [1, 2]), default_transform): + matrix[i] = t transform.matrix = matrix transforms = Transforms() for c in tqdm(goodch, desc="Calculating channel transforms"): # noqa - if c == masterch: + if c == main_channel: transforms[im.channel_names[c]] = transform else: - transforms[im.channel_names[c]] = Transform.register(max_ims[masterch], max_ims[c]) * transform + transforms[im.channel_names[c]] = Transform.register(max_ims[main_channel], max_ims[c]) * transform return transforms @staticmethod - def save_channel_transform_tiff(bead_files, tiffile): + def save_channel_transform_tiff(bead_files, tiffile, default_transform=None): from . import Imread n_channels = 0 @@ -232,7 +239,7 @@ class Transforms(dict): with IJTiffFile(tiffile) as tif: for t, file in enumerate(bead_files): with Imread(file) as im: - with Imread(file).with_transform() as jm: + with Imread(file).with_transform(default_transform=default_transform) as jm: for c in range(im.shape["c"]): tif.save(np.hstack((im(c=c, t=0).max("z"), jm(c=c, t=0).max("z"))), c, 0, t) diff --git a/pyproject.toml b/pyproject.toml index 6448879..a5193d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ndbioimage" -version = "2026.1.0" +version = "2026.1.1" description = "Bio image reading, metadata and some affine registration." authors = [ { name = "W. Pomp", email = "w.pomp@nki.nl" }