def create_bookmark_file(df, output_path=None, default_text=None): """ Create a NeuTu bookmark file from a set of points. Args: df: DataFrame with columns ['x', 'y', 'z'], and optionally 'body' and 'text' output_path: If given, the bookmark file will be written to the given path. default_text: Optional. If provided, any rows without a 'text' entry will be given this text. Returns: dict, the contents of a bookmarks file. (Typically, you'll just ignore the output and use the output_path argument instead.) """ df = df.copy() if df.index.name == 'body': df['body'] = df.index assert set(df.columns) >= {*'xyz'}, "Input must contain columns for x,y,z" df['location'] = df[[*'xyz']].apply(list, axis=1) if 'body' in df.columns: df['body ID'] = df['body'] if default_text: if 'text' in df.columns: blank_rows = df.eval('text.isnull() or text == ""') df.loc[blank_rows, 'text'] = default_text else: df['text'] = default_text cols = {'location', 'body ID', 'text'} & {*df.columns} data = df[cols].to_dict('records') # Does any of this metadata actually matter? metadata = { "description": "bookmarks", "date": datetime.datetime.now().strftime("%d-%B-%Y %H:%M"), "username": getpass.getuser(), "computer": os.uname().nodename, "session path": os.getcwd(), "coordinate system": "dvid", "software": __name__, "software version": "0", "software revision": "0", "file version": 1, } contents = {"metadata": metadata, "data": data} if output_path: dump_json(contents, output_path, unsplit_int_lists=True) return contents
def create_precomputed_segment_properties(names, bucket_name, bucket_path, localdir=None): """ Write the "segment properties" for a neuroglancer precomputed volume, i.e. the segment names. """ if not bucket_name.startswith('gs://'): bucket_name = 'gs://' + bucket_name if localdir is None: localdir = bucket_path.split('/')[-1] os.makedirs(f"{localdir}/segment_properties", exist_ok=True) props = { "@type": "neuroglancer_segment_properties", "inline": { "ids": [], "properties": [ { "id": "source", "type": "label", "values": [] } ] } } for label, name in names.items(): props["inline"]["ids"].append(str(label)) props["inline"]["properties"][0]["values"].append(name) dump_json(props, f"{localdir}/segment_properties/info", unsplit_int_lists=True) subprocess.run(f"gsutil cp {bucket_name}/{bucket_path}/info {localdir}/info", shell=True) with open(f"{localdir}/info", 'r') as f: info = json.load(f) info["segment_properties"] = "segment_properties" dump_json(info, f"{localdir}/info", unsplit_int_lists=True) subprocess.run(f"gsutil cp {localdir}/info {bucket_name}/{bucket_path}/info", shell=True) subprocess.run(f"gsutil cp -R {localdir}/segment_properties {bucket_name}/{bucket_path}/segment_properties", shell=True)
def create_precomputed_ngmeshes(vol, vol_fullres_box, names, bucket_name, bucket_path, localdir=None, decimation=0.01): """ Create meshes for the given labelvolume and upload them to a google bucket in neuroglancer legacy mesh format (i.e. what flyem calls "ngmesh" format). """ from vol2mesh import Mesh if not bucket_name.startswith('gs://'): bucket_name = 'gs://' + bucket_name if localdir is None: localdir = bucket_path.split('/')[-1] os.makedirs(f"{localdir}/mesh", exist_ok=True) dump_json({"@type": "neuroglancer_legacy_mesh"}, f"{localdir}/mesh/info") logger.info("Generating meshes") meshes = Mesh.from_label_volume(vol, vol_fullres_box, smoothing_rounds=2) logger.info("Simplifying meshes") for mesh in meshes.values(): mesh.simplify(decimation) logger.info("Serializing meshes") for label, mesh in meshes.items(): name = names.get(label, str(label)) mesh.serialize(f"{localdir}/mesh/{name}.ngmesh") dump_json({"fragments": [f"{name}.ngmesh"]}, f"{localdir}/mesh/{label}:0") subprocess.run(f"gsutil cp {bucket_name}/{bucket_path}/info {localdir}/info", shell=True) with open(f"{localdir}/info", 'r') as f: info = json.load(f) info["mesh"] = "mesh" dump_json(info, f"{localdir}/info", unsplit_int_lists=True) logger.info("Uploading") subprocess.run(f"gsutil cp {localdir}/info {bucket_name}/{bucket_path}/info", shell=True) subprocess.run(f"gsutil cp -R {localdir}/mesh {bucket_name}/{bucket_path}/mesh", shell=True)
def edges_to_assignment(df, gray_source, seg_source, sv_as_body=False, output_path=None, shuffle=False, description=""): if isinstance(df, str): df = pd.read_csv(df) assert isinstance(df, pd.DataFrame) dupes = df.duplicated(['sv_a', 'sv_b']).sum() if dupes: print(f"Dropping {dupes} duplicate tasks!") df = df.drop_duplicates(['sv_a', 'sv_b']) print(f"Writing {len(df)} tasks") if shuffle: print("Shuffling task order") df = df.sample(frac=1) tasks = [] for row in df.itertuples(): body_a, body_b = row.body_a, row.body_b box_a = [[row.body_box_x0_a, row.body_box_y0_a, row.body_box_z0_a], [row.body_box_x1_a, row.body_box_y1_a, row.body_box_z1_a]] box_b = [[row.body_box_x0_b, row.body_box_y0_b, row.body_box_z0_b], [row.body_box_x1_b, row.body_box_y1_b, row.body_box_z1_b]] box_a = np.asarray(box_a) box_b = np.asarray(box_b) sv_box_a = [[row.sv_box_x0_a, row.sv_box_y0_a, row.sv_box_z0_a], [row.sv_box_x1_a, row.sv_box_y1_a, row.sv_box_z1_a]] sv_box_b = [[row.sv_box_x0_b, row.sv_box_y0_b, row.sv_box_z0_b], [row.sv_box_x1_b, row.sv_box_y1_b, row.sv_box_z1_b]] sv_box_a = np.asarray(sv_box_a) sv_box_b = np.asarray(sv_box_b) if sv_as_body: # If presenting the task as if the supervoxels were the body, # then overwrite the body items with the supervoxel info instead. body_a, body_b = row.sv_a, row.sv_b box_a, box_b = sv_box_a, sv_box_b edge_info = {} for col in df.columns: if 'box' not in col: edge_info[col] = getattr(row, col) task = { "task type": "body merge", "supervoxel ID 1": row.sv_a, "supervoxel ID 2": row.sv_b, "supervoxel point 1": [row.xa, row.ya, row.za], "supervoxel point 2": [row.xb, row.yb, row.zb], "body point 1": [row.xa, row.ya, row.za], "body point 2": [row.xb, row.yb, row.zb], "default body ID 1": body_a, "default body ID 2": body_b, "edge_info": edge_info } # Only add the bounding box keys if the box is legit # (Apparently the export contains NaNs sometimes and I'm not sure why...) if not np.isnan(box_a).any(): box_a = box_a.astype(int).tolist() task["default bounding box 1"] = { "minvoxel": box_a[0], "maxvoxel": box_a[1] } if not np.isnan(box_b).any(): box_b = box_b.astype(int).tolist() task["default bounding box 2"] = { "minvoxel": box_b[0], "maxvoxel": box_b[1] } tasks.append(task) assignment = { "file type": "Neu3 task list", "file version": 1, "grayscale source": gray_source, "segmentation source": seg_source, "task list": tasks } if description: assignment["task set description"] = description assignment = convert_nans(assignment) if output_path: dump_json(assignment, output_path, unsplit_int_lists=True) return assignment