Source code for patato.convenience_scripts.copy_rois

#  Copyright (c) Thomas Else 2023-25.
#  License: MIT

import argparse
import glob
import re
from os.path import join

import h5py
import numpy as np
from ..utils import sort_key


[docs] def init_argparse(): map = { "TRUE": True, "FALSE": False, "T": True, "F": False, "YES": True, "NO": False, "Y": True, "N": False, } def map_fn(x): return map[x.upper()] parser = argparse.ArgumentParser( description="Copy ROIs between scans made of same thing at same time." ) parser.add_argument("input", type=str, help="Data Folder") parser.add_argument( "-r", "--regex", default=None, type=str, help="Regex for parsing name" ) parser.add_argument( "-c", "--copyclose", default=False, type=map_fn, help="Automatically copy over roi to closest " "slice if not exact matches (tolerance " "1mm)", ) parser.add_argument( "-d", "--deleteold", default=True, type=map_fn, help="Delete old copies." ) parser.add_argument( "-j", "--justdeletecopies", default=False, type=map_fn, help="Just delete copies of rois.", ) parser.add_argument( "-f", "--copyfrom", default=None, help="Copy only from scan type (e.g. OE)." ) parser.add_argument( "-t", "--copyto", default=None, help="Copy only to scan type (e.g. DCE)." ) return parser
[docs] def main(): p = init_argparse() args = p.parse_args() DATA_FOLDER = args.input regex = args.regex if args.regex is None: regex = r"^(?P<mouse>[^_\- ]+)[_\- ](?P<ear>[^_\- ]+)[_\- ]((?P<scan_number>[0-9]+)[_\- ])?(?P<scan_type>.+)$" elif args.regex == "tom": regex = r"^(?P<date>[0-9]+)\-(?P<mouse>.+)\-(?P<scan_type>.+)" elif args.regex == "marilena": regex = r"VMstudy_MEO#(?P<number>[0-9]+)_((Day(?P<day>[0-9]+))|MSOT)_?(?P<scan_type>GS|SS|MS|GC|again)?" regex = re.compile(regex) scan_groups = {} for file in sorted( glob.glob(join(DATA_FOLDER, "**", "*.hdf5"), recursive=True), key=sort_key ): data = h5py.File(file, "r") name_regex = regex.fullmatch(data["raw_data"].attrs["name"]) print(file, data["raw_data"].attrs["name"], name_regex) if name_regex is None: continue name_regex = name_regex.groupdict() scan_group = [] for k in name_regex: if k != "scan_type": if name_regex[k] is not None: scan_group.append(name_regex[k]) else: scan_group.append("1") scan_group = "-".join(scan_group) if scan_group not in scan_groups: scan_groups[scan_group] = [file] else: scan_groups[scan_group].append(file) data.close() for group in scan_groups: rois = [] roi_attrs = [] roi_names = [] roi_numbers = [] roi_scan_origin = [] for file in scan_groups[group]: data = h5py.File(file, "r+") if args.copyfrom is not None: if args.copyfrom not in data["raw_data"].attrs["name"]: continue if "rois" in data: for a in data["rois"]: deletion = False # track whether any rois deleted so we can renumber at the end for b in data["rois"][a]: if data["rois"][a][b].attrs.get("copy", default=False): if args.deleteold or args.justdeletecopies: del data["rois"][a][b] deletion = True continue rois.append(data["rois"][a][b][:]) roi_attrs.append(dict(data["rois"][a][b].attrs)) roi_names.append(a) roi_numbers.append(b) roi_scan_origin.append(data["raw_data"].attrs["name"]) if deletion: original = sorted(list(data["rois"][a].keys()), key=int) change = [str(x) for x in range(len(original))] for old, new in zip(original, change): data["rois"][a].move(old, new) data.close() for file in scan_groups[group]: data = h5py.File(file, "r+") if args.copyto is not None: if args.copyto not in data["raw_data"].attrs["name"]: continue for roi, att, nam, num, ori in zip( rois, roi_attrs, roi_names, roi_numbers, roi_scan_origin ): if ori != data["raw_data"].attrs["name"]: zs = np.unique(data["Z-POS"][:]) make_copy = False if att["z"] in zs: # print("Able to copy from", ori, data["raw_data"].attrs["name"]) make_copy = True elif np.any(np.isclose(zs, att["z"], atol=1, rtol=0)): print( "Not exact, but close for: ", ori, "to", data["raw_data"].attrs["name"], ) copy = ( input("Not exact match, copy anyway? Y/[N]") if not args.copyclose else True ) if copy in ["Y", "y", True]: make_copy = True old_z = att["z"] att["z"] = zs[np.argmin(np.abs(zs - att["z"]))] print( "Copying, changing z from {:.2f} to {:.2f}".format( old_z, att["z"] ) ) else: # print("No close positions for: ", ori, "to", data["raw_data"].attrs["name"], "so skipping.") # print(zs[np.argmin(np.abs(zs - att["z"]))], att["z"]) # print(np.isclose(zs, att["z"], atol=0.1, rtol=0)) make_copy = False if make_copy and not args.justdeletecopies: # copy the roi to scan roi_grp = data.require_group("rois") roi_grp = roi_grp.require_group(nam) roi_num = str(len(roi_grp.keys())) roi_data = roi_grp.create_dataset(roi_num, data=roi) roi_data.attrs["copy"] = True for a in att: roi_data.attrs[a] = att[a] data.close()