diff --git a/model_server/base/roiset.py b/model_server/base/roiset.py index a66f97414c61b163403abfb75d96c119f616400b..7c3b3ae907a0ae8ccc1e709cfa2ae8f5b8e58ed8 100644 --- a/model_server/base/roiset.py +++ b/model_server/base/roiset.py @@ -203,7 +203,7 @@ class RoiSet(object): query_str = query_str + f' & {k} > {vmin} & {k} < {vmax}' return df.loc[df.query(query_str).index, :] - def get_df(self) -> pd.DataFrame: # TODO: exclude columns that refer to objects + def get_df(self) -> pd.DataFrame: return self._df def get_slices(self) -> pd.Series: @@ -212,7 +212,7 @@ class RoiSet(object): def add_df_col(self, name, se: pd.Series) -> None: self._df[name] = se - def get_multichannel_projection(self): # TODO: document and test + def get_multichannel_projection(self): if self.count: projected = project_stack_from_focal_points( self._df['centroid-0'].to_numpy(), @@ -225,8 +225,6 @@ class RoiSet(object): projected = self.acc_raw.data.max(axis=-1) return projected - # TODO: remove, since padding is implicit in PatchStack - # TODO: test case where patch channel is restricted def get_raw_patches(self, channel=None, pad_to=256, make_3d=False): # padded, un-annotated 2d patches if channel: patches_df = self.get_patches(white_channel=channel, pad_to=pad_to) diff --git a/model_server/base/util.py b/model_server/base/util.py index 0d35d3c4bf267c95bc8e9527db473407f75f9c1b..112118832acb0d15caed1ef29118c3bcc43ea7df 100644 --- a/model_server/base/util.py +++ b/model_server/base/util.py @@ -79,11 +79,12 @@ def loop_workflow( output_folder_path: str, workflow_func: callable, models: List[Model], - params: dict, + # params: dict, export_batch_csvs: bool = True, write_intermediate_products: bool = True, catch_and_continue: bool = True, chunk_size: int = None, + **params, ): """ Iteratively call the specified workflow function on each of a list of input files diff --git a/model_server/extensions/chaeo/batch_jobs/20231026_Porto.py b/model_server/extensions/chaeo/batch_jobs/20231026_Porto.py deleted file mode 100644 index 17b83355d9855d32182dc20c2b30c48523a40ecd..0000000000000000000000000000000000000000 --- a/model_server/extensions/chaeo/batch_jobs/20231026_Porto.py +++ /dev/null @@ -1,56 +0,0 @@ -from pathlib import Path - -from model_server.base.util import autonumber_new_directory, get_matching_files, loop_workflow -from model_server.extensions.chaeo.ecotaxa import write_ecotaxa_tsv -from model_server.extensions.chaeo.workflows import export_patches_from_multichannel_zstack -from model_server.extensions.ilastik.models import IlastikPixelClassifierModel - - -if __name__ == '__main__': - sample_id = '20231026-porto' - root = Path('c:/Users/rhodes/projects/proj0012-trec-handoff/owncloud-sync/TREC-HD/Images/') - where_czi = (root / 'TREC_STOP_26_Porto/231026_automic/20231026-152512_lowzoom_data/LowZoom').__str__() - where_output = autonumber_new_directory( - 'c:/Users/rhodes/projects/proj0011-plankton-seg/exp0022/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/model_server/extensions/chaeo/examples/batch_obj_cla.py b/model_server/extensions/chaeo/examples/batch_obj_cla.py index eef5e70343061d6a47d09aac236395df141d1c17..752c50c56fb2054a5b6d947d753e1edfa1c97534 100644 --- a/model_server/extensions/chaeo/examples/batch_obj_cla.py +++ b/model_server/extensions/chaeo/examples/batch_obj_cla.py @@ -3,7 +3,7 @@ from pathlib import Path from model_server.conf.testing import output_path from model_server.base.util import autonumber_new_directory, get_matching_files, loop_workflow from extensions.ilastik.models import PatchStackObjectClassifier -from model_server.extensions.chaeo.workflows import infer_object_map_from_zstack +from model_server.extensions.chaeo.workflows import export_zstack_roiset from model_server.extensions.ilastik.models import IlastikPixelClassifierModel @@ -36,7 +36,7 @@ if __name__ == '__main__': loop_workflow( input_files, where_output, - infer_object_map_from_zstack, + export_zstack_roiset, models, params, catch_and_continue=False, diff --git a/model_server/extensions/chaeo/batch_jobs/20230807_kristineberg_spiked.py b/model_server/extensions/chaeo/old_batch_jobs/20230807_kristineberg_spiked.py similarity index 100% rename from model_server/extensions/chaeo/batch_jobs/20230807_kristineberg_spiked.py rename to model_server/extensions/chaeo/old_batch_jobs/20230807_kristineberg_spiked.py diff --git a/model_server/extensions/chaeo/batch_jobs/20231008_Bilbao_PA.py b/model_server/extensions/chaeo/old_batch_jobs/20231008_Bilbao_PA.py similarity index 100% rename from model_server/extensions/chaeo/batch_jobs/20231008_Bilbao_PA.py rename to model_server/extensions/chaeo/old_batch_jobs/20231008_Bilbao_PA.py diff --git a/model_server/extensions/chaeo/batch_jobs/20231023_Porto_4ch.py b/model_server/extensions/chaeo/old_batch_jobs/20231023_Porto_4ch.py similarity index 100% rename from model_server/extensions/chaeo/batch_jobs/20231023_Porto_4ch.py rename to model_server/extensions/chaeo/old_batch_jobs/20231023_Porto_4ch.py diff --git a/model_server/extensions/chaeo/batch_jobs/20231023_Porto_EtOHfixed.py b/model_server/extensions/chaeo/old_batch_jobs/20231023_Porto_EtOHfixed.py similarity index 100% rename from model_server/extensions/chaeo/batch_jobs/20231023_Porto_EtOHfixed.py rename to model_server/extensions/chaeo/old_batch_jobs/20231023_Porto_EtOHfixed.py diff --git a/model_server/extensions/chaeo/batch_jobs/20231023_Porto_Live.py b/model_server/extensions/chaeo/old_batch_jobs/20231023_Porto_Live.py similarity index 100% rename from model_server/extensions/chaeo/batch_jobs/20231023_Porto_Live.py rename to model_server/extensions/chaeo/old_batch_jobs/20231023_Porto_Live.py diff --git a/model_server/extensions/chaeo/old_batch_jobs/20231026_Porto.py b/model_server/extensions/chaeo/old_batch_jobs/20231026_Porto.py new file mode 100644 index 0000000000000000000000000000000000000000..2448034658889dfe5fa105a8c43257fbfb55e308 --- /dev/null +++ b/model_server/extensions/chaeo/old_batch_jobs/20231026_Porto.py @@ -0,0 +1,103 @@ +from pathlib import Path + +from model_server.base.roiset import RoiSetMetaParams, RoiSetExportParams +from model_server.base.util import autonumber_new_directory, get_matching_files, loop_workflow +from model_server.extensions.chaeo.ecotaxa import write_ecotaxa_tsv +from model_server.extensions.chaeo.workflows import export_zstack_roiset +from model_server.extensions.ilastik.models import IlastikPixelClassifierModel + + +if __name__ == '__main__': + sample_id = '20231026-porto' + root = Path('y:/TREC_STOP_26_Porto/MobileLab/LSM900') + where_czi = (root / '231026_automic/20231026-152512_lowzoom_data/LowZoom').__str__() + where_output = autonumber_new_directory( + 'c:/Users/rhodes/projects/proj0011-plankton-seg/exp0022/output', + 'batch-output' + ) + + # px_ilp = Path('c:/Users/rhodes/projects/proj0011-plankton-seg/exp0017/pxAF405_dim8bit.ilp').__str__() + px_ilp = Path( + 'y:/TREC_Heidelberg/LSM900/Tina/20240109_automic/ilastik/pxAF405-8bit-embedded.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, + } + + roi_params = RoiSetMetaParams(**{ + 'mask_type': 'boxes', + 'filters': { + 'area': {'min': 1e3, 'max': 1e8} + }, + 'expand_box_by': [128, 2] + }) + + export_params = RoiSetExportParams(**{ + 'pixel_probabilities': True, + 'patches_3d': {}, + 'annotated_patches_2d': { + 'draw_bounding_box': True, + 'rgb_overlay_channels': [1, None, None], + 'rgb_overlay_weights': [0.2, 1.0, 1.0], + 'pad_to': 512, + }, + 'patches_2d': { + 'draw_bounding_box': False, + # 'draw_mask': False, + }, + # 'patch_masks': { + # 'pad_to': 256, + # }, + 'annotated_zstacks': {}, + 'object_classes': True, + 'dataframe': True, + }) + + input_files = get_matching_files(where_czi, 'czi', coord_filter={}) + + models = { + 'pixel_classifier': { + 'model': IlastikPixelClassifierModel(params={'project_file': Path(px_ilp)}), + 'params': { + 'px_class': 0, + 'px_prob_threshold': 0.25, + } + }, + } + + loop_workflow( + input_files, + where_output, + export_zstack_roiset, + models, + # params, + segmentation_channel=params['segmentation_channel'], + patches_channel=params['patches_channel'], + export_params=export_params, + roi_params=roi_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/model_server/extensions/chaeo/old_batch_jobs/__init__.py b/model_server/extensions/chaeo/old_batch_jobs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/model_server/extensions/chaeo/batch_jobs/coloring_book.py b/model_server/extensions/chaeo/old_batch_jobs/coloring_book.py similarity index 100% rename from model_server/extensions/chaeo/batch_jobs/coloring_book.py rename to model_server/extensions/chaeo/old_batch_jobs/coloring_book.py diff --git a/model_server/extensions/chaeo/batch_jobs/int_test_20231028_Porto_PA.py b/model_server/extensions/chaeo/old_batch_jobs/int_test_20231028_Porto_PA.py similarity index 95% rename from model_server/extensions/chaeo/batch_jobs/int_test_20231028_Porto_PA.py rename to model_server/extensions/chaeo/old_batch_jobs/int_test_20231028_Porto_PA.py index 6007943bc394d0d17a751621e2273ef0260de3e6..4248d80e509257d325efbc0675c479026a94b9a1 100644 --- a/model_server/extensions/chaeo/batch_jobs/int_test_20231028_Porto_PA.py +++ b/model_server/extensions/chaeo/old_batch_jobs/int_test_20231028_Porto_PA.py @@ -3,7 +3,7 @@ from pathlib import Path from model_server.base.util import autonumber_new_directory, get_matching_files, loop_workflow from model_server.extensions.chaeo.ecotaxa import write_ecotaxa_tsv_chunked_subdirectories from extensions.chaeo import ZMaskExportParams -from model_server.extensions.chaeo.workflows import infer_object_map_from_zstack +from model_server.extensions.chaeo.workflows import export_zstack_roiset from model_server.extensions.ilastik.models import IlastikPixelClassifierModel @@ -64,7 +64,7 @@ if __name__ == '__main__': loop_workflow( input_files, where_output, - infer_object_map_from_zstack, + export_zstack_roiset, [IlastikPixelClassifierModel(params={'project_file': Path(px_ilp)})], params, catch_and_continue=False, diff --git a/model_server/extensions/chaeo/batch_jobs/proj0004-exp0038-fixed.py b/model_server/extensions/chaeo/old_batch_jobs/proj0004-exp0038-fixed.py similarity index 100% rename from model_server/extensions/chaeo/batch_jobs/proj0004-exp0038-fixed.py rename to model_server/extensions/chaeo/old_batch_jobs/proj0004-exp0038-fixed.py diff --git a/model_server/extensions/chaeo/router.py b/model_server/extensions/chaeo/router.py index decf71c6852b41fe2295776f14ba43d2ca4559b8..87d75074f2819d24069146080d9321b9985207a8 100644 --- a/model_server/extensions/chaeo/router.py +++ b/model_server/extensions/chaeo/router.py @@ -1,6 +1,6 @@ from fastapi import APIRouter -from model_server.extensions.chaeo.workflows import infer_object_map_from_zstack +from model_server.extensions.chaeo.workflows import export_zstack_roiset from model_server.base.session import Session from model_server.base.validators import validate_workflow_inputs @@ -25,7 +25,7 @@ def infer_px_then_ob_maps( inpath = session.paths['inbound_images'] / input_filename validate_workflow_inputs([px_model_id, ob_model_id], [inpath]) - record = infer_object_map_from_zstack( + record = export_zstack_roiset( inpath, session.paths['outbound_images'], [ diff --git a/model_server/extensions/chaeo/tests/test_roiset_workflow.py b/model_server/extensions/chaeo/tests/test_roiset_workflow.py index 53c830b830d3519d9a17ff798a84c691f6724ea0..a52fd11f650a2fd5d5ee0656b9b03ad2aa7b1aab 100644 --- a/model_server/extensions/chaeo/tests/test_roiset_workflow.py +++ b/model_server/extensions/chaeo/tests/test_roiset_workflow.py @@ -3,7 +3,7 @@ import unittest from model_server.base.models import DummyInstanceSegmentationModel from model_server.base.roiset import RoiSetMetaParams, RoiSetExportParams from model_server.conf.testing import output_path, roiset_test_data -from model_server.extensions.chaeo.workflows import infer_object_map_from_zstack +from model_server.extensions.chaeo.workflows import export_zstack_roiset from model_server.extensions.ilastik.models import IlastikPixelClassifierModel from tests.test_roiset import BaseTestRoiSetMonoProducts @@ -56,7 +56,7 @@ class TestRoiSetWorkflow(BaseTestRoiSetMonoProducts, unittest.TestCase): 'dataframe': True, }) - infer_object_map_from_zstack( + export_zstack_roiset( roiset_test_data['multichannel_zstack']['path'], output_path / 'roiset' / 'workflow', models, diff --git a/model_server/extensions/chaeo/workflows.py b/model_server/extensions/chaeo/workflows.py index c651f95ecdf68f4b8f3aa431e6d4e512a2467aa4..b6f362e1ba54418876acd6cde310232c2a7b286c 100644 --- a/model_server/extensions/chaeo/workflows.py +++ b/model_server/extensions/chaeo/workflows.py @@ -17,7 +17,7 @@ from model_server.base.models import Model, InstanceSegmentationModel, SemanticS from model_server.base.workflows import Timer -def infer_object_map_from_zstack( +def export_zstack_roiset( input_file_path: str, output_folder_path: str, models: List[Model], @@ -27,9 +27,7 @@ def infer_object_map_from_zstack( roi_params: RoiSetMetaParams = RoiSetMetaParams(), export_params: RoiSetExportParams = RoiSetExportParams(), ) -> Dict: - assert len(models) == 2 assert isinstance(models['pixel_classifier']['model'], SemanticSegmentationModel) - assert isinstance(models['object_classifier']['model'], InstanceSegmentationModel) ti = Timer() stack = generate_file_accessor(Path(input_file_path)) @@ -51,12 +49,15 @@ def infer_object_map_from_zstack( rois = RoiSet(stack, _get_label_ids(mip_mask), params=roi_params) ti.click('generate_zmasks') - rois.classify_by( - models['object_classifier']['name'], - patches_channel, - models['object_classifier']['model'] - ) - ti.click('classify_objects') + # optionally classify if an object classifier is passed + if 'object_classifier' in models.keys(): + assert isinstance(models['object_classifier']['model'], InstanceSegmentationModel) + rois.classify_by( + models['object_classifier']['name'], + patches_channel, + models['object_classifier']['model'] + ) + ti.click('classify_objects') rois.run_exports(Path(output_folder_path), patches_channel, fstem, export_params) ti.click('export_roi_products')