diff --git a/extensions/chaeo/tests/test_zstack.py b/extensions/chaeo/tests/test_zstack.py index 6c398d24b99dbe1d6874cc3b742e92a0a23cad16..3ce9596945ad844c7f8841e0c9ee5808485f35cb 100644 --- a/extensions/chaeo/tests/test_zstack.py +++ b/extensions/chaeo/tests/test_zstack.py @@ -27,7 +27,7 @@ class TestZStackDerivedDataProducts(unittest.TestCase): # write_accessor_data_to_file(output_path / 'obmap.tif', self.obmap) def test_zmask_makes_correct_boxes(self, mask_type='boxes', **kwargs): - zmask, meta = build_zmask_from_object_mask( + zmask, meta, df = build_zmask_from_object_mask( self.obmap.get_one_channel_data(0), self.stack.get_one_channel_data(0), mask_type=mask_type, diff --git a/extensions/chaeo/workflows.py b/extensions/chaeo/workflows.py index 9e836713cc380fce243fc8dfe4930010e9141744..997826eee276f2e8c66895903a023a0ba0ef9754 100644 --- a/extensions/chaeo/workflows.py +++ b/extensions/chaeo/workflows.py @@ -11,7 +11,7 @@ from extensions.chaeo.zmask import build_zmask_from_object_mask from model_server.accessors import generate_file_accessor, InMemoryDataAccessor, write_accessor_data_to_file from model_server.workflows import Timer -def export_patches_from_multichannel_zstack( # TODO: PyDantic model for arguments +def export_patches_from_multichannel_zstack( input_zstack_path: Path, px_model: IlastikPixelClassifierModel, pxmap_threshold: float, @@ -49,7 +49,7 @@ def export_patches_from_multichannel_zstack( # TODO: PyDantic model for argumen ti.click('threshold_pixel_mask') # make zmask - zmask, zmask_meta = build_zmask_from_object_mask( + zmask, zmask_meta, df = build_zmask_from_object_mask( obmask.get_one_channel_data(pixel_class), stack.get_one_channel_data(zmask_channel), mask_type=mask_type, @@ -88,4 +88,5 @@ def export_patches_from_multichannel_zstack( # TODO: PyDantic model for argumen 'number_of_objects': len(zmask_meta), 'success': True, 'timer_results': ti.events, + 'dataframe': df, } \ No newline at end of file diff --git a/extensions/chaeo/zmask.py b/extensions/chaeo/zmask.py index 19c1db5780027be8e734f9403d326158c436e816..8304b836f9ce57c6bc75545f72a35f8d24bbc795 100644 --- a/extensions/chaeo/zmask.py +++ b/extensions/chaeo/zmask.py @@ -21,13 +21,15 @@ def build_zmask_from_object_mask( :param mask_type: if 'boxes', zmask is True in each object's complete bounding box; otherwise 'contours' :param expand_box_by: (xy, z) expands bounding box by (xy, z) pixels except where this hits a boundary :return: tuple (zmask, meta) - np.ndarray zmask: boolean mask of same size as stack - meta: List containing one Dict per object, with keys: + np.ndarray: + boolean mask of same size as stack + List containing one Dict per object, with keys: info: object's properties from skimage.measure.regionprops_table, including bounding box (y0, y1, x0, x1) slice: named slice (np.s_) of (optionally) expanded bounding box relative_bounding_box: bounding box (y0, y1, x0, x1) in relative frame of (optionally) expanded bounding box contour: object's contour returned by skimage.measure.find_contours mask: mask of object in relative frame of (optionally) expanded bounding box + pd.DataFrame: objects, including bounding, box information after filtering """ # validate inputs @@ -131,4 +133,4 @@ def build_zmask_from_object_mask( sl = bb['slice'] zi_st[sl] = 1 - return zi_st, meta \ No newline at end of file + return zi_st, meta, df \ No newline at end of file diff --git a/extensions/ilastik/examples/batch_run_patches.py b/extensions/ilastik/examples/batch_run_patches.py index c985d818215d7497ea3766bd184b7ba49db2a07a..5b67bb3dd70e6cfdda2bc980c59481709c862aea 100644 --- a/extensions/ilastik/examples/batch_run_patches.py +++ b/extensions/ilastik/examples/batch_run_patches.py @@ -1,5 +1,7 @@ from pathlib import Path +import pandas as pd + from extensions.chaeo.workflows import export_patches_from_multichannel_zstack from extensions.ilastik.models import IlastikPixelClassifierModel @@ -10,16 +12,18 @@ if __name__ == '__main__': where_output = Path( 'c:/Users/rhodes/projects/proj0011-plankton-seg/exp0009/batch_output' ) + csv_args = {'mode': 'w', 'header': True} # when creating file px_ilp = Path.home() / 'model-server' / 'ilastik' / 'AF405-bodies_boundaries.ilp' px_model = IlastikPixelClassifierModel( params={'project_file': px_ilp} ) + for ff in where_czi.iterdir(): print(ff) if not ff.suffix.upper() == '.CZI': continue - export_patches_from_multichannel_zstack( + result = export_patches_from_multichannel_zstack( input_zstack_path=where_czi/ff, px_model=px_model, pxmap_threshold=0.6, @@ -32,3 +36,13 @@ if __name__ == '__main__': zmask_expand_box_by=(64, 3), ) + # parse and record results + df = result['dataframe'] + df['filename'] = ff.name + df.to_csv(where_output / 'df_objects.csv', **csv_args) + pd.DataFrame(result['timer_results'], index=[0]).to_csv(where_output / 'timer_results.csv', **csv_args) + csv_args = {'mode': 'a', 'header': False} # append to CSV from here on + + + +