diff --git a/model_server/extensions/chaeo/examples/export_patch_focus_metrics.py b/model_server/extensions/chaeo/examples/export_patch_focus_metrics.py deleted file mode 100644 index 6063af5331efa7bad58224362a59d4be675a3442..0000000000000000000000000000000000000000 --- a/model_server/extensions/chaeo/examples/export_patch_focus_metrics.py +++ /dev/null @@ -1,164 +0,0 @@ -from pathlib import Path -import re -from time import localtime, strftime -from typing import Dict - -import pandas as pd - -from model_server.extensions.ilastik.models import IlastikPixelClassifierModel -from model_server.extensions.chaeo.products import export_3d_patches_with_focus_metrics, export_patches_from_zstack -from model_server.extensions.chaeo.zmask import RoiSet -from model_server.base.accessors import generate_file_accessor, InMemoryDataAccessor, write_accessor_data_to_file -from model_server.base.workflows import Timer - - -def export_patch_focus_metrics_from_multichannel_zstack( - input_zstack_path: str, - ilastik_project_file: str, - pxmap_threshold: float, - pixel_class: int, - zmask_channel: int, - patches_channel: int, - where_output: str, - mask_type: str = 'boxes', - zmask_filters: Dict = None, - zmask_expand_box_by: int = None, - annotate_focus_metric=None, - **kwargs, -) -> Dict: - - ti = Timer() - stack = generate_file_accessor(Path(input_zstack_path)) - fstem = Path(input_zstack_path).stem - ti.click('file_input') - assert stack.nz > 1, 'Expecting z-stack' - - # MIP and classify pixels - mip = InMemoryDataAccessor( - stack.get_one_channel_data(channel=0).data.max(axis=-1, keepdims=True) - ) - px_model = IlastikPixelClassifierModel( - params={'project_file': Path(ilastik_project_file)} - ) - pxmap, _ = px_model.infer(mip) - ti.click('infer_pixel_probability') - - obmask = InMemoryDataAccessor( - pxmap.data > pxmap_threshold - ) - ti.click('threshold_pixel_mask') - - # make zmask - # zmask, zmask_meta, df, interm = build_zmask_from_object_mask( - # obmask.get_one_channel_data(pixel_class), - # stack.get_one_channel_data(zmask_channel), - # mask_type=mask_type, - # filters=zmask_filters, - # expand_box_by=zmask_expand_box_by, - # ) - obj_table = RoiSet( - obmask.get_one_channel_data(pixel_class), - stack.get_one_channel_data(zmask_channel), - mask_type=mask_type, - filters=zmask_filters, - expand_box_by=zmask_expand_box_by, - ) - zmask_acc = InMemoryDataAccessor(obj_table.zmask) - ti.click('generate_zmasks') - - files = export_3d_patches_with_focus_metrics( - Path(where_output) / '3d_patches', - stack.get_one_channel_data(patches_channel), - obj_table.zmask_meta, - prefix=fstem, - rescale_clip=0.0, - make_3d=True, - annotate_focus_metric=annotate_focus_metric, - ) - ti.click('export_3d_patches') - - files = export_patches_from_zstack( - Path(where_output) / '2d_patches', - stack.get_one_channel_data(patches_channel), - obj_table.zmask_meta, - prefix=fstem, - draw_bounding_box=True, - rescale_clip=0.0, - # focus_metric=lambda x: np.max(sobel(x)), - focus_metric='max_sobel', - make_3d=False, - ) - ti.click('export_2d_patches') - - return { - 'pixel_model_id': px_model.model_id, - 'input_filepath': input_zstack_path, - 'number_of_objects': len(obj_table.zmask_meta), - 'success': True, - 'timer_results': ti.events, - 'dataframe': df, - 'interm': obj_table.interm, - } - -if __name__ == '__main__': - where_czi = Path( - 'c:/Users/rhodes/projects/proj0004-marine-photoactivation/data/exp0038/AutoMic/20230906-163415/Selection' - ) - - where_output_root = Path( - 'c:/Users/rhodes/projects/proj0011-plankton-seg/exp0009/output' - ) - yyyymmdd = strftime('%Y%m%d', localtime()) - idx = 0 - while Path(where_output_root / f'batch-output-{yyyymmdd}-{idx:04d}').exists(): - idx += 1 - where_output = Path( - where_output_root / f'batch-output-{yyyymmdd}-{idx:04d}' - ) - - csv_args = {'mode': 'w', 'header': True} # when creating file - px_ilp = Path.home() / 'model_server' / 'ilastik' / 'AF405-bodies_boundaries.ilp' - - for ff in where_czi.iterdir(): - if ff.stem != 'Selection--W0000--P0009-T0001': - continue - - pattern = 'Selection--W([\d]+)--P([\d]+)-T([\d]+)' - ma = re.match(pattern, ff.stem) - - print(ff) - if not ff.suffix.upper() == '.CZI': - continue - if int(ma.groups()[1]) > 10: # skip second half of set - continue - - export_kwargs = { - 'input_zstack_path': (where_czi / ff).__str__(), - 'ilastik_project_file': px_ilp.__str__(), - 'pxmap_threshold': 0.25, - 'pixel_class': 0, - 'zmask_channel': 0, - 'patches_channel': 4, - 'where_output': where_output.__str__(), - 'mask_type': 'boxes', - 'zmask_filters': {'area': (1e3, 1e8)}, - 'zmask_expand_box_by': (128, 3), - 'annotate_focus_metric': 'max_sobel' - } - - result = export_patch_focus_metrics_from_multichannel_zstack(**export_kwargs) - - # 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) - pd.json_normalize(export_kwargs).to_csv(where_output / 'workflow_params.csv', **csv_args) - csv_args = {'mode': 'a', 'header': False} # append to CSV from here on - - # export intermediate data if flagged - for k in result['interm'].keys(): - write_accessor_data_to_file( - where_output / k / (ff.stem + '.tif'), - InMemoryDataAccessor(result['interm'][k]) - ) \ No newline at end of file diff --git a/model_server/extensions/chaeo/products.py b/model_server/extensions/chaeo/products.py index d001114f1ed9164c194e6a1814149d3b3fb96658..679271eeb00129545a2c495a655250a8bd26dece 100644 --- a/model_server/extensions/chaeo/products.py +++ b/model_server/extensions/chaeo/products.py @@ -97,7 +97,7 @@ def get_patches_from_zmask_meta( patches = [] # for mi in zmask_meta: - for i, roi in enumerate(roiset.get_df().itertuples()): + for i, roi in enumerate(roiset.get_df().itertuples()): # TODO: call RoiSet.iter() when implemented # sl = roi['slice'] # rbb = mi['relative_bounding_box'] # TODO: call rel_ fields in DF @@ -204,7 +204,7 @@ def export_patches_from_zstack( ) exported = [] - for i, roi in enumerate(roiset.get_df().itertuples()): + for i, roi in enumerate(roiset.get_df().itertuples()): # just used for label info # for i in range(0, len(zmask_meta)): # mi = zmask_meta[i] patch = patches_acc.iat_yxcz(i) @@ -224,86 +224,6 @@ def export_patches_from_zstack( }) return exported -def export_3d_patches_with_focus_metrics( - where: Path, - stack: GenericImageDataAccessor, - zmask_meta: list, - rescale_clip: float = 0.0, - pad_to: int = 256, - prefix='patch', - **kwargs -): - """ - Export 3D patches as multi-level z-stacks, along with CSV of various focus methods for each z-position - - :param kwargs: - annotate_focus_metric: name focus metric to use when drawing bounding box at optimal focus z-position - :return: - list of exported files - """ - assert stack.chroma == 1, 'Expecting monochromatic image data' - assert stack.nz > 1, 'Expecting z-stack' - - def get_zstack_focus_metrics(zs): - nz = zs.shape[3] - me = _focus_metrics() - dd = {} - for zi in range(0, nz): - spf = zs[:, :, :, zi] - dd[zi] = {k: me[k](spf) for k in me.keys()} - return dd - - exported = [] - patch_meta = [] - for mi in zmask_meta: - obj = mi['info'] - sl = mi['slice'] - rbb = mi['relative_bounding_box'] # TODO: use rel_ fields in DF - idx = mi['df_index'] - - patch = stack.data[sl] - - assert len(patch.shape) == 4 - assert patch.shape[2] == stack.chroma - - if rescale_clip is not None: - patch = rescale(patch, rescale_clip) - - # unpack relative bounding box and define subset of patch data - x0 = rbb['x0'] - y0 = rbb['y0'] - x1 = rbb['x1'] - y1 = rbb['y1'] - sp_sl = np.s_[y0: y1, x0: x1, :, :] - subpatch = patch[sp_sl] - - # compute focus metrics for all z-levels - me_dict = get_zstack_focus_metrics(subpatch) - patch_meta.append({'label': obj.label, 'zi': obj.zi, 'metrics': me_dict}) - me_df = pd.DataFrame(me_dict).T - - # drawing bounding box only on focused slice - ak = kwargs.get('annotate_focus_metric') - if ak and ak in me_df.columns: - zi_foc = me_df.idxmax().to_dict()[ak] - patch[:, :, 0, zi_foc] = draw_box_on_patch( - patch[:, :, 0, zi_foc], - ((x0, y0), (x1, y1)), - ) - - if pad_to: - patch = pad(patch, pad_to) - - fstem = f'{prefix}-la{obj.label:04d}-zi{obj.zi:04d}' - write_patch_to_file(where, fstem + '.tif', resample_to_8bit(patch)) - me_df.to_csv(where / (fstem + '.csv')) - exported.append({ - 'df_index': idx, - 'patch_filename': fstem + '.tif', - 'focus_metrics_filename': fstem + '.csv', - }) - - return exported def export_multichannel_patches_from_zstack( where: Path,