diff --git a/flamingo_tools/measurements.py b/flamingo_tools/measurements.py index a7ed2d4..8488f7e 100644 --- a/flamingo_tools/measurements.py +++ b/flamingo_tools/measurements.py @@ -2,7 +2,7 @@ import os from concurrent import futures from functools import partial -from typing import Optional +from typing import List, Optional import numpy as np import pandas as pd @@ -12,6 +12,7 @@ from .file_utils import read_image_data from .segmentation.postprocessing import compute_table_on_the_fly +import flamingo_tools.s3_utils as s3_utils def _measure_volume_and_surface(mask, resolution): @@ -175,6 +176,8 @@ def compute_object_measures( resolution: float = 0.38, force: bool = False, feature_set: str = "default", + s3_flag: bool = False, + component_list: List[int] = [], ) -> None: """Compute simple intensity and morphology measures for each segmented cell in a segmentation. @@ -201,9 +204,17 @@ def compute_object_measures( # First, we load the pre-computed segmentation table from MoBIE. if segmentation_table_path is None: table = None + elif s3_flag: + seg_table, fs = s3_utils.get_s3_path(segmentation_table_path) + with fs.open(seg_table, 'r') as f: + table = pd.read_csv(f, sep="\t") else: table = pd.read_csv(segmentation_table_path, sep="\t") + # filter table with largest component + if len(component_list) != 0 and "component_labels" in table.columns: + table = table[table['component_labels'].isin(component_list)] + # Then, open the volumes. image = read_image_data(image_path, image_key) segmentation = read_image_data(segmentation_path, segmentation_key) diff --git a/reproducibility/block_extraction/repro_block_extraction.py b/reproducibility/block_extraction/repro_block_extraction.py index fefd99f..4d96fb9 100644 --- a/reproducibility/block_extraction/repro_block_extraction.py +++ b/reproducibility/block_extraction/repro_block_extraction.py @@ -7,7 +7,7 @@ def repro_block_extraction( - ddict: dict, + json_file: str, output_dir: str, s3_credentials: Optional[str] = None, s3_bucket_name: Optional[str] = None, @@ -17,7 +17,7 @@ def repro_block_extraction( tif_flag = True input_key = "s0" - with open(ddict, 'r') as myfile: + with open(json_file, 'r') as myfile: data = myfile.read() param_dicts = json.loads(data) diff --git a/reproducibility/object_measures/2025-06-IHC-Apha_object_measures.json b/reproducibility/object_measures/2025-06-IHC-Apha_object_measures.json new file mode 100644 index 0000000..b071311 --- /dev/null +++ b/reproducibility/object_measures/2025-06-IHC-Apha_object_measures.json @@ -0,0 +1,24 @@ +[ + { + "cochlea": "M_AMD_OTOF1_L", + "image_channel": [ + "Apha" + ], + "segmentation_channel": "IHC_v2", + "component_list": [ + 1, + 20 + ] + }, + { + "cochlea": "M_AMD_OTOF2_L", + "image_channel": [ + "Apha" + ], + "segmentation_channel": "IHC_v2", + "component_list": [ + 1, + 2 + ] + } +] diff --git a/reproducibility/object_measures/2025-06-SGN-PV-GFP_object_measures.json b/reproducibility/object_measures/2025-06-SGN-PV-GFP_object_measures.json new file mode 100644 index 0000000..e41f194 --- /dev/null +++ b/reproducibility/object_measures/2025-06-SGN-PV-GFP_object_measures.json @@ -0,0 +1,46 @@ +[ + { + "cochlea": "M_LR_000144_L", + "image_channel": [ + "PV_resized", + "GFP_resized" + ], + "segmentation_channel": "SGN_resized_v2", + "component_list": [ + 1 + ] + }, + { + "cochlea": "M_LR_000145_L", + "image_channel": [ + "PV_resized", + "GFP_resized" + ], + "segmentation_channel": "SGN_resized_v2", + "component_list": [ + 1 + ] + }, + { + "cochlea": "M_LR_000151_R", + "image_channel": [ + "PV_resized", + "GFP_resized" + ], + "segmentation_channel": "SGN_resized_v2", + "component_list": [ + 1 + ] + }, + { + "cochlea": "M_LR_000155_L", + "image_channel": [ + "PV_resized", + "GFP_resized" + ], + "segmentation_channel": "SGN_resized_v2", + "component_list": [ + 1 + ] + } +] diff --git a/reproducibility/object_measures/repro_object_measures.py b/reproducibility/object_measures/repro_object_measures.py new file mode 100644 index 0000000..a1b2d49 --- /dev/null +++ b/reproducibility/object_measures/repro_object_measures.py @@ -0,0 +1,84 @@ +import argparse +import json +import os +from typing import Optional + +import flamingo_tools.s3_utils as s3_utils +from flamingo_tools.measurements import compute_object_measures + + +def repro_object_measures( + json_file: str, + output_dir: str, + s3_credentials: Optional[str] = None, + s3_bucket_name: Optional[str] = None, + s3_service_endpoint: Optional[str] = None, +): + s3_flag = True + input_key = "s0" + + with open(json_file, 'r') as myfile: + data = myfile.read() + param_dicts = json.loads(data) + + for dic in param_dicts: + cochlea = dic["cochlea"] + image_channels = dic["image_channel"] if isinstance(dic["image_channel"], list) else [dic["image_channel"]] + seg_channel = dic["segmentation_channel"] + component_list = dic["component_list"] + print(f"Processing cochlea {cochlea}") + + for img_channel in image_channels: + + print(f"Processing image channel {img_channel}") + cochlea_str = "-".join(cochlea.split("_")) + img_str = "-".join(img_channel.split("_")) + seg_str = "-".join(seg_channel.split("_")) + output_table_path = os.path.join(output_dir, f"{cochlea_str}_{img_str}_{seg_str}_object-measures.tsv") + + img_s3 = f"{cochlea}/images/ome-zarr/{img_channel}.ome.zarr" + seg_s3 = f"{cochlea}/images/ome-zarr/{seg_channel}.ome.zarr" + seg_table_s3 = f"{cochlea}/tables/{seg_channel}/default.tsv" + + img_path, fs = s3_utils.get_s3_path(img_s3, bucket_name=s3_bucket_name, + service_endpoint=s3_service_endpoint, credential_file=s3_credentials) + seg_path, fs = s3_utils.get_s3_path(seg_s3, bucket_name=s3_bucket_name, + service_endpoint=s3_service_endpoint, credential_file=s3_credentials) + + compute_object_measures( + image_path=img_path, + segmentation_path=seg_path, + segmentation_table_path=seg_table_s3, + output_table_path=output_table_path, + image_key=input_key, + segmentation_key=input_key, + s3_flag=s3_flag, + component_list=component_list) + + +def main(): + parser = argparse.ArgumentParser( + description="Script to extract region of interest (ROI) block around center coordinate.") + + parser.add_argument('-i', '--input', type=str, required=True, help="Input JSON dictionary.") + parser.add_argument('-o', "--output", type=str, required=True, help="Output directory.") + + parser.add_argument("--s3_credentials", type=str, default=None, + help="Input file containing S3 credentials. " + "Optional if AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY were exported.") + parser.add_argument("--s3_bucket_name", type=str, default=None, + help="S3 bucket name. Optional if BUCKET_NAME was exported.") + parser.add_argument("--s3_service_endpoint", type=str, default=None, + help="S3 service endpoint. Optional if SERVICE_ENDPOINT was exported.") + + args = parser.parse_args() + + repro_object_measures( + args.input, args.output, + args.s3_credentials, args.s3_bucket_name, args.s3_service_endpoint, + ) + + +if __name__ == "__main__": + + main()