"""Build a MedCLIPSeg dataset for the neurofilament task (no manual masks needed). For every CZI with an IMARIS _Statistics folder, writes: data/Neurofilament/_Folder/img/.png (neurofilament MIP, RGB) data/Neurofilament/_Folder/label/.png (IMARIS-reconstruction mask) data/Neurofilament/Prompts_Folder/_text.xlsx (Image, Ground Truth, Description) The mask is the k-NN reconstruction of IMARIS's traced skeleton from its segment coordinates (dilated) — the same approximate label used elsewhere. Splits are by ANIMAL so validation/test are unseen animals. Then fine-tune the bundled model: cd reference_medclipseg python train.py --config-file configs/Neurofilament.yaml # needs a CUDA GPU Honest note: this label is approximate (reconstructed, not IMARIS's exact voxel mask), and the target is IMARIS's over-traced tangle — see README. """ import argparse, glob, os, sys import numpy as np import pandas as pd from scipy import ndimage as ndi from scipy.spatial import cKDTree from skimage.transform import resize from skimage.io import imsave sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import processing as P ROOT = "/Users/slf20757/Desktop/Dr. Fernandes" SIZE = 224 PROMPT = "a fluorescence microscopy image of neurofilament nerve fibers" # animal -> split VAL = {"C1"} TEST = {"C2b"} def seg_xyz(sd, stem): def cols(name, nc): r = [] for line in open(os.path.join(sd, f"{stem}_{name}.csv"), errors="ignore"): p = line.split(",") try: r.append([float(p[i]) for i in range(nc)]) except (ValueError, IndexError): pass return np.array(r) return cols("Segment_Position", 3) def skel_mask(pos, voxel, shape_yx, k=3): dz, dy, dx = voxel; ny, nx = shape_yx col = pos[:, 0] / dx * (SIZE / nx); row = pos[:, 1] / dy * (SIZE / ny) pts = np.stack([row, col], 1) tree = cKDTree(pts); dist, idx = tree.query(pts, k=min(k + 1, len(pts))) radius = 2.0 / dx * (SIZE / nx) m = np.zeros((SIZE, SIZE), bool) for i in range(len(pts)): for j, d in zip(idx[i, 1:], dist[i, 1:]): if d <= radius: p0, p1 = pts[i], pts[j] n = max(int(np.abs(p1 - p0).max()) + 1, 2) t = np.linspace(0, 1, n)[:, None]; line = p0 + t * (p1 - p0) m[np.clip(line[:, 0].astype(int), 0, SIZE - 1), np.clip(line[:, 1].astype(int), 0, SIZE - 1)] = True return ndi.binary_dilation(m, iterations=1) def main(): ap = argparse.ArgumentParser() ap.add_argument("--out", default="data/Neurofilament") ap.add_argument("--limit", type=int, default=0, help="cap images (for testing)") args = ap.parse_args() rows = {"Train": [], "Val": [], "Test": []} n = 0 for csv in sorted(glob.glob(os.path.join(ROOT, "*", "*_Statistics", "*_Filament_Length_(sum).csv"))): sd = os.path.dirname(csv) stem = os.path.basename(csv).replace("_Filament_Length_(sum).csv", "") animal = os.path.relpath(csv, ROOT).split(os.sep)[0] czi = os.path.join(ROOT, animal, stem.replace(" filament", "") + ".czi") if not (os.path.exists(czi) and os.path.exists(os.path.join(sd, f"{stem}_Segment_Position_X.csv"))): continue split = "Val" if animal in VAL else "Test" if animal in TEST else "Train" img = P.load_image(czi); nf, _ = P.guess_channels(img) vol = img.data[nf]; ny, nx = vol.shape[1], vol.shape[2] mip = resize(P.channel_preview(vol), (SIZE, SIZE), preserve_range=True).astype(np.uint8) mask = (skel_mask(seg_xyz(sd, stem), img.voxel, (ny, nx)) * 255).astype(np.uint8) name = stem.replace(" ", "_") + ".png" for sub in ("img", "label"): os.makedirs(os.path.join(args.out, f"{split}_Folder", sub), exist_ok=True) imsave(os.path.join(args.out, f"{split}_Folder", "img", name), np.stack([mip] * 3, -1)) imsave(os.path.join(args.out, f"{split}_Folder", "label", name), mask) rows[split].append({"Image": name, "Ground Truth": name, "Description": PROMPT}) n += 1 print(f"[{split}] {stem}: mask px={int((mask>0).sum())}", flush=True) del img, vol if args.limit and n >= args.limit: break os.makedirs(os.path.join(args.out, "Prompts_Folder"), exist_ok=True) for split, r in rows.items(): if r: pd.DataFrame(r).to_excel( os.path.join(args.out, "Prompts_Folder", f"{split}_text.xlsx"), index=False) print(f"\nDone. Train={len(rows['Train'])} Val={len(rows['Val'])} " f"Test={len(rows['Test'])} -> {args.out}") print("Now fine-tune (GPU): cd reference_medclipseg && " "python train.py --config-file configs/Neurofilament.yaml") if __name__ == "__main__": main()