Spaces:
Sleeping
Sleeping
File size: 3,510 Bytes
028d06c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | """
Generate a synthetic two-arm demo case set (data/cases.json + placeholder SRH-like images) so the app runs
with ZERO real data. Replace with real cases for the study: put images + cases.json in a PRIVATE HF dataset
and set CASES_DATASET.
Case schema (data-driven; the app reads exactly this):
Arm A (realism): {"case_id": "...", "arm": "A", "image": "img/x.png", "true_source": "real"|"synthetic"|"synthetic_ungated"}
Arm B (category): {"case_id": "...", "arm": "B", "cluster_id": "...", "images": ["img/..","img/.."],
"is_control": "none"|"positive"|"negative"}
- true_source (A) and is_control/cluster_id (B) are hidden from the reader; used only in backend analysis.
- The reader is blinded; the app shuffles item order per reader.
"""
import json
import random
from pathlib import Path
from PIL import Image, ImageDraw, ImageFilter
HERE = Path(__file__).parent
DATA = HERE / "data"
IMG = DATA / "img"
IMG.mkdir(parents=True, exist_ok=True)
W = H = 300
def srh_patch(seed, family=0):
"""Pseudo-SRH texture: purple/pink base (CH2/CH3-like) with cellular blobs + noise. family sets a look."""
rnd = random.Random(seed * 131 + family * 7)
base = [(60, 30, 70), (40, 55, 60), (70, 40, 55)][family % 3]
im = Image.new("RGB", (W, H), base)
d = ImageDraw.Draw(im, "RGBA")
for _ in range(rnd.randint(40, 90)):
x, y = rnd.randint(0, W), rnd.randint(0, H)
r = rnd.randint(4, 16)
col = (rnd.randint(150, 230), rnd.randint(90, 160), rnd.randint(150, 220), rnd.randint(60, 140))
d.ellipse([x - r, y - r, x + r, y + r], fill=col)
im = im.filter(ImageFilter.GaussianBlur(rnd.uniform(0.4, 1.2)))
return im
cases = []
# --- Arm A: 8 single patches, half labelled real, half synthetic (+ one ungated synthetic) ---
labels = ["real", "real", "real", "synthetic", "synthetic", "synthetic", "synthetic_ungated", "real"]
for i, src in enumerate(labels):
cid = f"A{i+1:03d}"
srh_patch(i + 1, family=i % 3).save(IMG / f"{cid}.png")
cases.append({"case_id": cid, "arm": "A", "image": f"img/{cid}.png", "true_source": src})
# --- Arm B: 3 clusters (positive control = coherent, negative control = scrambled, one 'discovered') ---
def cluster(cid, cluster_id, is_control, imgs):
return {"case_id": cid, "arm": "B", "cluster_id": cluster_id, "is_control": is_control, "images": imgs}
# positive control: 6 patches, same family (coherent)
pos = []
for k in range(6):
p = f"img/Bpos_{k}.png"; srh_patch(100 + k, family=1).save(IMG / f"Bpos_{k}.png"); pos.append(p)
cases.append(cluster("B001", "pos_ctrl", "positive", pos))
# negative control: 6 patches, mixed families (scrambled / incoherent)
neg = []
for k in range(6):
p = f"img/Bneg_{k}.png"; srh_patch(200 + k, family=k % 3).save(IMG / f"Bneg_{k}.png"); neg.append(p)
cases.append(cluster("B002", "neg_ctrl", "negative", neg))
# a 'discovered' cluster: 6 patches, one family with a couple outliers
disc = []
for k in range(6):
fam = 2 if k < 4 else (k % 3)
p = f"img/Bdisc_{k}.png"; srh_patch(300 + k, family=fam).save(IMG / f"Bdisc_{k}.png"); disc.append(p)
cases.append(cluster("B003", "disc_01", "none", disc))
with open(DATA / "cases.json", "w", encoding="utf-8") as f:
json.dump({"study": "SRH Pathology Validation Study (demo)", "cases": cases}, f, indent=2)
print(f"wrote {DATA/'cases.json'} with {len(cases)} demo cases "
f"({sum(1 for c in cases if c['arm']=='A')} Arm-A, {sum(1 for c in cases if c['arm']=='B')} Arm-B).")
|