CoolFace
Apppublic

bigaxon/kinetic

sourceHugging Faceotherupdated 1y agoView on Hugging Face
0likes
model_runner.py151 linesDownload Raw Back to root
1# model_runner.py2# 🔬 Kinetic Pathology — production-safe core (no UI, no launch)3 4import warnings, os5import numpy as np, pandas as pd, matplotlib; matplotlib.use("Agg")6import matplotlib.pyplot as plt7from typing import Optional, List8from datetime import datetime9from scipy.spatial.distance import cdist10from scipy.optimize import linear_sum_assignment11from skimage import io as skio, exposure, filters, morphology, measure, color12from skimage.restoration import denoise_tv_chambolle13 14warnings.filterwarnings("ignore")15 16try:17    import cv2  # optional18    CV2_AVAILABLE = True19except Exception:20    CV2_AVAILABLE = False21 22_TMP_DIR = "/tmp/kinetic"23os.makedirs(_TMP_DIR, exist_ok=True)24 25def _safe_path(name: str) -> str:26    return os.path.join(_TMP_DIR, name)27 28def _blank_png(path: str, text: str):29    fig = plt.figure(figsize=(4, 2.5), dpi=150)30    ax = fig.add_subplot(111)31    ax.text(0.5, 0.5, text, ha="center", va="center", fontsize=9)32    ax.axis("off")33    fig.tight_layout()34    fig.savefig(path, bbox_inches="tight")35    plt.close(fig)36 37def _empty_csv(path: str, cols: List[str]):38    import csv39    with open(path, "w", newline="") as f:40        csv.writer(f).writerow(cols)41 42def _fmt_sig2(x) -> str:43    try:44        xv = float(x)45    except Exception:46        return "nan"47    if not np.isfinite(xv) or xv == 0:48        return "0"49    s = f"{xv:.2g}"50    if ("e" in s or "E" in s) and 1e-2 <= abs(xv) < 1e4:51        mag = int(np.floor(np.log10(abs(xv))))52        norm = xv / (10 ** mag)53        s = f"{norm:.2f}e{mag:+d}"54    return s55 56def _df_preview(df: Optional[pd.DataFrame], n: int = 10) -> pd.DataFrame:57    if df is None: return pd.DataFrame()58    try: return df.head(n).copy()59    except Exception: return pd.DataFrame()60 61def run(62    video_path: str,63    max_frames: int,64    tv_weight: float,65    min_area: int,66    max_area: int,67    opening_radius: int,68    max_link_distance: float,69    use_um: bool,70    px_um: float,71    show_ids: bool,72    show_trails: bool,73    trail_len: int,74    circle_sz: int,75    do_emergent: bool,76    auto_center: bool,77    lesion_cx: Optional[float],78    lesion_cy: Optional[float],79    neighbor_radius: float,80):81    """Return exactly 11 outputs for the Gradio UI."""82    if not video_path or not os.path.exists(video_path):83        summary = "Please upload a valid video file."84        report_path   = _safe_path("report_placeholder.png");  _blank_png(report_path, "No video")85        counts_path   = _safe_path("counts_placeholder.png");  _blank_png(counts_path, "Counts")86        traj_path     = _safe_path("traj_placeholder.png");    _blank_png(traj_path, "Trajectories")87        origin_path   = _safe_path("origin_placeholder.png");  _blank_png(origin_path, "Origin")88        tracks_csv    = _safe_path("tracks.csv");              _empty_csv(tracks_csv, ["track_id","t","x","y"])89        feats_csv     = _safe_path("features.csv");            _empty_csv(feats_csv, ["cell_id","area","speed"])90        return (summary, report_path, "", "",91                counts_path, traj_path, origin_path,92                tracks_csv, feats_csv, pd.DataFrame(), pd.DataFrame())93 94    try:95        # ====== STUB ANALYSIS (replace later with real code) ======96        n_frames_scanned = 097        means = []98        if CV2_AVAILABLE:99            cap = None100            try:101                import cv2102                cap = cv2.VideoCapture(video_path)103                while n_frames_scanned < min(max_frames, 30):104                    ok, frame = cap.read()105                    if not ok: break106                    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)107                    means.append(float(gray.mean()))108                    n_frames_scanned += 1109            finally:110                if cap is not None: cap.release()111        avg_intensity = np.mean(means) if means else np.nan112        unit = "µm/s" if use_um else "px/s"113 114        summary = (115            f"Kinetic Pathology (stub)\n"116            f"- Frames scanned: {n_frames_scanned}/{max_frames}\n"117            f"- Avg intensity: {_fmt_sig2(avg_intensity)}\n"118            f"- Units: {unit}\n"119        )120 121        ts = datetime.now().strftime("%Y%m%d_%H%M%S")122        report_path = _safe_path(f"report_{ts}.png"); _blank_png(report_path, "Report (stub)")123        counts_path = _safe_path(f"counts_{ts}.png"); _blank_png(counts_path, "Counts (stub)")124        traj_path   = _safe_path(f"traj_{ts}.png");   _blank_png(traj_path, "Trajectories (stub)")125        origin_path = _safe_path(f"origin_{ts}.png"); _blank_png(origin_path, "Origin (stub)")126 127        orig_vid_path = video_path128        over_vid_path = ""  # supply when you produce an overlay129 130        tracks_csv = _safe_path(f"tracks_{ts}.csv");  _empty_csv(tracks_csv, ["track_id","t","x","y"])131        feats_csv  = _safe_path(f"features_{ts}.csv"); _empty_csv(feats_csv, ["cell_id","area","speed"])132        feats_prev  = pd.DataFrame({"cell_id":[], "area":[], "speed":[]})133        tracks_prev = pd.DataFrame({"track_id":[], "t":[], "x":[], "y":[]})134        # ====== END STUB ======135 136        return (summary, report_path, orig_vid_path, over_vid_path,137                counts_path, traj_path, origin_path,138                tracks_csv, feats_csv, _df_preview(feats_prev), _df_preview(tracks_prev))139 140    except Exception as e:141        err = f"Analysis failed: {type(e).__name__}: {e}"142        report_path = _safe_path("report_error.png"); _blank_png(report_path, "Error")143        counts_path = _safe_path("counts_error.png"); _blank_png(counts_path, "Counts error")144        traj_path   = _safe_path("traj_error.png");   _blank_png(traj_path, "Traj error")145        origin_path = _safe_path("origin_error.png"); _blank_png(origin_path, "Origin error")146        tracks_csv  = _safe_path("tracks_error.csv"); _empty_csv(tracks_csv, ["track_id","t","x","y"])147        feats_csv   = _safe_path("features_error.csv"); _empty_csv(feats_csv, ["cell_id","area","speed"])148        return (err, report_path, "", "",149                counts_path, traj_path, origin_path,150                tracks_csv, feats_csv, pd.DataFrame(), pd.DataFrame())151