import argparse,json from collections import Counter from pathlib import Path import numpy as np from irstd.data import read_manifest,read_pair,sha from irstd.core import components,centers def main(): p=argparse.ArgumentParser();p.add_argument('--manifest',required=True);p.add_argument('--out',required=True);a=p.parse_args() rows=read_manifest(a.manifest);areas=[];dist=[];sizes=Counter();counts=[];empty=0 for r in rows: x,y=read_pair(r);ms=components(y);areas.extend(int(m.sum()) for m in ms);counts.append(len(ms));empty+=not len(ms) sizes[str(x.shape)]+=1;c=centers(ms) if len(c)>1: d=np.linalg.norm(c[:,None]-c[None,:],axis=-1);np.fill_diagonal(d,np.inf);dist.extend(d.min(1).tolist()) def quant(v):return dict(zip(['min','q25','median','q75','max'],map(float,np.quantile(v,[0,.25,.5,.75,1])))) if v else None result=dict(manifest_sha256=sha(a.manifest),splits=dict(Counter(r['split'] for r in rows)), groups=len(set(r['group'] for r in rows)),resolutions=dict(sizes),empty_images=empty, target_area_pixels=quant(areas),targets_per_image=quant(counts),nearest_target_distance=quant(dist), area_bins={'1-4':sum(1<=v<=4 for v in areas),'5-9':sum(5<=v<=9 for v in areas),'10-25':sum(10<=v<=25 for v in areas),'26+':sum(v>=26 for v in areas)}, image_hashes={r['id']:sha(r['image']) for r in rows},mask_hashes={r['id']:sha(r['mask']) for r in rows}, limitations='Does not verify licensing, missing annotations, visual near-duplicates, source identities, or independence.') Path(a.out).write_text(json.dumps(result,indent=2)) if __name__=='__main__':main()