From 977038556cb28fbcea09e00fa421c612c38ff71d Mon Sep 17 00:00:00 2001 From: Christopher Rhodes <christopher.rhodes@embl.de> Date: Sun, 22 Oct 2023 09:28:48 +0200 Subject: [PATCH] Querying image scale in workflow output, but hitting error --- conf/testing.py | 1 + extensions/chaeo/util.py | 1 + extensions/chaeo/workflows.py | 1 + model_server/accessors.py | 21 +++++++++++++++++++-- tests/test_accessors.py | 6 +++++- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/conf/testing.py b/conf/testing.py index f2df5040..3c52b95c 100644 --- a/conf/testing.py +++ b/conf/testing.py @@ -10,6 +10,7 @@ czifile = { 'h': 1274, 'c': 5, 'z': 1, + 'um_per_pixel': 1/3.9881, } filename = 'rgb.png' diff --git a/extensions/chaeo/util.py b/extensions/chaeo/util.py index b127d937..e966ce3e 100644 --- a/extensions/chaeo/util.py +++ b/extensions/chaeo/util.py @@ -7,6 +7,7 @@ import pandas as pd from model_server.accessors import InMemoryDataAccessor, write_accessor_data_to_file def autonumber_new_directory(where: str, prefix: str) -> str: + Path(where).mkdir(parents=True, exist_ok=True) yyyymmdd = strftime('%Y%m%d', localtime()) idx = 0 diff --git a/extensions/chaeo/workflows.py b/extensions/chaeo/workflows.py index 5e1b4e3c..dab8215d 100644 --- a/extensions/chaeo/workflows.py +++ b/extensions/chaeo/workflows.py @@ -175,6 +175,7 @@ def export_patches_from_multichannel_zstack( 'pixel_model_id': px_model.model_id, 'input_filepath': input_file_path, 'number_of_objects': len(zmask_meta), + 'pixeL_scale_in_micrometers': stack.pixel_scale_in_micrometers, 'success': True, 'timer_results': ti.events, 'dataframe': df, diff --git a/model_server/accessors.py b/model_server/accessors.py index b6e5da1f..caec8ddf 100644 --- a/model_server/accessors.py +++ b/model_server/accessors.py @@ -37,13 +37,19 @@ class GenericImageDataAccessor(ABC): if self._data.dtype == 'bool': return True elif self._data.dtype == 'uint8': - return np.all(np.unique(self._data) == [0, 255]) + unique = np.unique(self._data) + if unique.shape[0] == 2 and np.all(unique == [0, 255]): + return True return False def get_one_channel_data (self, channel: int): c = int(channel) return InMemoryDataAccessor(self.data[:, :, c:(c+1), :]) + @property + def pixel_scale_in_micrometers(self): + return None + @property def dtype(self): return self.data.dtype @@ -163,12 +169,23 @@ class CziImageFileAccessor(GenericImageFileAccessor): [cf.axes.index(ch) for ch in idx], [0, 1, 2, 3] ) - self._data = self.conform_data(yxcz.reshape(yxcz.shape[0:4])) def __del__(self): self.czifile.close() + @property + def pixel_scale_in_micrometers(self): + meta_sc_str = self.czifile.metadata(raw=False)['ImageDocument']['Metadata']['ImageScaling']['ImagePixelSize'] + meta_mags = self.czifile.metadata(raw=False)['ImageDocument']['Metadata']['ImageScaling']['ScalingComponent'] + sc_xy = list(map( + float, + meta_sc_str.split(',') + )) + assert sc_xy[0] == sc_xy[1] + mags = [float(m['Magnification']) for m in meta_mags] + return sc_xy[0] / np.product(mags) + def write_accessor_data_to_file(fpath: Path, accessor: GenericImageDataAccessor, mkdir=True) -> bool: if mkdir: diff --git a/tests/test_accessors.py b/tests/test_accessors.py index f7a4341d..1a465dfb 100644 --- a/tests/test_accessors.py +++ b/tests/test_accessors.py @@ -110,4 +110,8 @@ class TestCziImageFileAccess(unittest.TestCase): def test_read_zstack_mono_mask(self): acc = generate_file_accessor(monozstackmask['path']) - self.assertTrue(acc.is_mask()) \ No newline at end of file + self.assertTrue(acc.is_mask()) + + def test_read_in_pixel_scale_from_czi(self): + cf = CziImageFileAccessor(czifile['path']) + self.assertAlmostEqual(cf.pixel_scale_in_micrometers, czifile['um_per_pixel'], places=3) \ No newline at end of file -- GitLab