Source code for unravel.cluster_stats.crop

#!/usr/bin/env python3

"""
Use ``cstats_crop`` from UNRAVEL to load image, load bounding box, crop cluster, and save as .nii.gz.

Note:
    - -x and -z need to be provided if the resolution is not extracted from the image metadata.
    - Use -a, -b, or -c to specify the crop method.

Usage with all clusters:
------------------------
    cstats_crop -i path/img.nii.gz -o path/output_img.nii.gz -a [-x $XY] [-z $Z] [-v]

Usage with a bounding box:
--------------------------
    cstats_crop -i path/img.nii.gz -o path/output_img.nii.gz -b path/bbox.txt [-x $XY] [-z $Z] [-v]
    
Usage with a cluster ID:
------------------------
    cstats_crop -i path/img.nii.gz -o path/output_img.nii.gz -c 1 [-x $XY] [-z $Z] [-v]
"""

from rich.traceback import install
from rich import print

from unravel.core.help_formatter import RichArgumentParser, SuppressMetavar, SM

from unravel.core.config import Configuration
from unravel.core.img_io import load_3D_img, save_as_nii
from unravel.core.img_tools import find_bounding_box, cluster_IDs, crop
from unravel.core.utils import log_command, verbose_start_msg, verbose_end_msg, load_text_from_file


[docs] def parse_args(): parser = RichArgumentParser(formatter_class=SuppressMetavar, add_help=False, docstring=__doc__) reqs = parser.add_argument_group('Required arguments') reqs.add_argument('-i', '--input', help='path/img.czi, path/img.nii.gz, or path/tif_dir', action=SM) opts = parser.add_argument_group('Optional args') opts.add_argument('-o', '--output', help='path/output_img.nii.gz', action=SM) opts.add_argument('-b', '--bbox', help='path/bbox.txt', action=SM) opts.add_argument('-c', '--cluster', help='Cluster ID/intensity to get bbox and crop', action=SM) opts.add_argument('-a', '--all_clusters', help='Crop each cluster. Default: False', action='store_true', default=False) opts.add_argument('-x', '--xy_res', help='xy voxel size in microns for the raw data', type=float, action=SM) opts.add_argument('-z', '--z_res', help='z voxel size in microns for the raw data', type=float, action=SM) general = parser.add_argument_group('General arguments') general.add_argument('-v', '--verbose', help='Increase verbosity. Default: False', action='store_true', default=False) return parser.parse_args()
[docs] def save_cropped_img(img_cropped, xy_res, z_res, args, cluster=None): if args.output: save_path = args.output elif args.bbox: save_path = args.input.replace('.nii.gz', f'_cropped.nii.gz') elif cluster is not None: save_path = args.input.replace('.nii.gz', f'_cluster{cluster}_cropped.nii.gz') else: print(" [red1]No output specified. Exiting.") exit() if max(img_cropped.flatten()) < 255: save_as_nii(img_cropped, save_path, xy_res, z_res, data_type='uint8') else: save_as_nii(img_cropped, save_path, xy_res, z_res, data_type='uint16')
[docs] @log_command def main(): install() args = parse_args() Configuration.verbose = args.verbose verbose_start_msg() if args.xy_res is None or args.z_res is None: img, xy_res, z_res = load_3D_img(args.input, return_res=True) else: img = load_3D_img(args.input, return_res=True) xy_res, z_res = args.xy_res, args.z_res # Crop image if args.bbox: bbox = load_text_from_file(args.bbox) img_cropped = crop(img, bbox) save_cropped_img(img_cropped, xy_res, z_res, args) elif args.cluster: xmin, xmax, ymin, ymax, zmin, zmax = find_bounding_box(img, cluster_ID=args.cluster) bbox_str = f"{xmin}:{xmax}, {ymin}:{ymax}, {zmin}:{zmax}" img_cropped = crop(img, bbox_str) save_cropped_img(img_cropped, xy_res, z_res, args, cluster=args.cluster) elif args.all_clusters: clusters = cluster_IDs(img, min_extent=1, print_IDs=False, print_sizes=False) for cluster in clusters: xmin, xmax, ymin, ymax, zmin, zmax = find_bounding_box(img, cluster_ID=cluster) bbox_str = f"{xmin}:{xmax}, {ymin}:{ymax}, {zmin}:{zmax}" img_cropped = crop(img, bbox_str) save_cropped_img(img_cropped, xy_res, z_res, args, cluster=cluster) else: print(" [red1]No bbox or cluster specified. Exiting.") exit() verbose_end_msg()
if __name__ == '__main__': main()