From 22d6190c15677751178be2fb4461d2a9413bad4b Mon Sep 17 00:00:00 2001 From: Christopher Rhodes <christopher.rhodes@embl.de> Date: Mon, 6 Nov 2023 17:43:37 +0100 Subject: [PATCH] A few workarounds with zero-length patch sets --- extensions/chaeo/accessors.py | 28 +++++++--- .../chaeo/batch_jobs/20231028_Porto_PA.py | 56 +++++++++++++++++++ extensions/chaeo/products.py | 2 + extensions/chaeo/workflows.py | 25 +++++---- 4 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 extensions/chaeo/batch_jobs/20231028_Porto_PA.py diff --git a/extensions/chaeo/accessors.py b/extensions/chaeo/accessors.py index f606470e..82f726ba 100644 --- a/extensions/chaeo/accessors.py +++ b/extensions/chaeo/accessors.py @@ -16,15 +16,25 @@ class MonoPatchStack(InMemoryDataAccessor): assert data.ndim == 3 self._data = np.expand_dims(data, 2) elif isinstance(data, list): # list of YX patches - nda = np.array(data).squeeze() - assert nda.ndim == 3 - self._data = np.expand_dims( - np.moveaxis( - nda, - [1, 2, 0], - [0, 1, 2]), - 2 - ) + if len(data) == 0: + self._data = np.ndarray([0, 0, 0, 0], dtype='uin9') + elif len(data) == 1: + self._data = np.expand_dims( + np.array( + data[0].squeeze() + ), + (2, 3) + ) + else: + nda = np.array(data).squeeze() + assert nda.ndim == 3 + self._data = np.expand_dims( + np.moveaxis( + nda, + [1, 2, 0], + [0, 1, 2]), + 2 + ) else: raise InvalidDataForPatchStackError(f'Cannot create accessor from {type(data)}') diff --git a/extensions/chaeo/batch_jobs/20231028_Porto_PA.py b/extensions/chaeo/batch_jobs/20231028_Porto_PA.py new file mode 100644 index 00000000..a4afbcdd --- /dev/null +++ b/extensions/chaeo/batch_jobs/20231028_Porto_PA.py @@ -0,0 +1,56 @@ +from pathlib import Path + +from model_server.util import autonumber_new_directory, get_matching_files, loop_workflow +from extensions.chaeo.ecotaxa import write_ecotaxa_tsv +from extensions.chaeo.workflows import export_patches_from_multichannel_zstack +from extensions.ilastik.models import IlastikPixelClassifierModel + + +if __name__ == '__main__': + sample_id = '20231028-porto-PA' + root = Path('c:/Users/rhodes/projects/proj0012-trec-handoff/owncloud-sync/TREC-HD/Images/') + where_czi = (root / 'TREC_STOP_26_Porto/Selection').__str__() + where_output = autonumber_new_directory( + 'c:/Users/rhodes/projects/proj0011-plankton-seg/exp0023/output', + 'batch-output' + ) + + px_ilp = Path('c:/Users/rhodes/projects/proj0011-plankton-seg/exp0017/pxAF405_dim8bit.ilp').__str__() + + params = { + 'pxmap_threshold': 0.25, + 'pxmap_foreground_channel': 0, + 'segmentation_channel': 0, + 'zmask_zindex': None, + 'patches_channel': 2, + 'zmask_type': 'boxes', + 'zmask_filters': {'area': (1e3, 1e8)}, + 'zmask_expand_box_by': (128, 3), + 'export_pixel_probabilities': True, + 'export_2d_patches_for_training': True, + 'draw_bounding_box_on_2d_patch': True, + 'export_2d_patches_for_annotation': True, + 'export_3d_patches': False, + 'export_annotated_zstack': True, + 'export_patch_masks': True, + 'zmask_clip': 0.01, + 'rgb_overlay_channels': (1, None, None), + 'rgb_overlay_weights': (0.2, 1.0, 1.0), + 'draw_label_on_zstack': True, + } + + input_files = get_matching_files(where_czi, 'czi', coord_filter={}) + + loop_workflow( + input_files, + where_output, + export_patches_from_multichannel_zstack, + [IlastikPixelClassifierModel(params={'project_file': Path(px_ilp)})], + params, + catch_and_continue=False, + ) + + csv_path = (Path(where_output) / 'workflow_data.csv').__str__() + write_ecotaxa_tsv(csv_path, where_output, sample_id=sample_id, scope_id='EMBL-MS-Zeiss-LSM900') + + print('Finished') \ No newline at end of file diff --git a/extensions/chaeo/products.py b/extensions/chaeo/products.py index a0291874..0f1ac976 100644 --- a/extensions/chaeo/products.py +++ b/extensions/chaeo/products.py @@ -120,6 +120,7 @@ def get_patches_from_zmask_meta( **kwargs ) -> MonoPatchStack: patches = [] + for mi in zmask_meta: sl = mi['slice'] @@ -197,6 +198,7 @@ def get_patches_from_zmask_meta( patch = pad(patch, pad_to) patches.append(patch) + if not make_3d and pc == 1: return MonoPatchStack(patches) else: diff --git a/extensions/chaeo/workflows.py b/extensions/chaeo/workflows.py index 57072bb8..119ee1ff 100644 --- a/extensions/chaeo/workflows.py +++ b/extensions/chaeo/workflows.py @@ -122,7 +122,7 @@ def export_patches_from_multichannel_zstack( ) ti.click('export_pixel_probability') - if export_3d_patches: + if export_3d_patches and len(zmask_meta) > 0: files = export_patches_from_zstack( Path(output_folder_path) / '3d_patches', stack.get_one_channel_data(patches_channel), @@ -134,7 +134,7 @@ def export_patches_from_multichannel_zstack( ) ti.click('export_3d_patches') - if export_2d_patches_for_annotation: + if export_2d_patches_for_annotation and len(zmask_meta) > 0: files = export_multichannel_patches_from_zstack( Path(output_folder_path) / '2d_patches_annotation', stack, @@ -159,7 +159,7 @@ def export_patches_from_multichannel_zstack( # prepopulate patch UUID df['patch_id'] = df.apply(lambda _: uuid4(), axis=1) - if export_2d_patches_for_training: + if export_2d_patches_for_training and len(zmask_meta) > 0: files = export_multichannel_patches_from_zstack( Path(output_folder_path) / '2d_patches_training', stack.get_one_channel_data(patches_channel), @@ -171,7 +171,7 @@ def export_patches_from_multichannel_zstack( ) ti.click('export_2d_patches') - if export_patch_masks: + if export_patch_masks and len(zmask_meta) > 0: files = export_patch_masks_from_zstack( Path(output_folder_path) / 'patch_masks', stack.get_one_channel_data(patches_channel), @@ -195,13 +195,16 @@ def export_patches_from_multichannel_zstack( # generate multichannel projection from label centroids dff = df[df['keeper']] - interm['projected'] = project_stack_from_focal_points( - dff['centroid-0'].to_numpy(), - dff['centroid-1'].to_numpy(), - dff['zi'].to_numpy(), - stack, - degree=4, - ) + if len(zmask_meta) > 0: + interm['projected'] = project_stack_from_focal_points( + dff['centroid-0'].to_numpy(), + dff['centroid-1'].to_numpy(), + dff['zi'].to_numpy(), + stack, + degree=4, + ) + else: # else just return MIP + interm['projected'] = stack.data.max(axis=-1) return { 'pixel_model_id': pixel_classifier.model_id, -- GitLab