- 新增 irstd 核心包、scripts、tests、configs - 新增研究文档:literature_review / mathematical_analysis / novelty_matrix / experiment_plan / research_decision / research_log / manuscript_outline - 新增 evidence、results 数据与审计产物 - 新增 pyproject.toml、requirements、.gitignore
45 lines
1.8 KiB
Python
45 lines
1.8 KiB
Python
import csv
|
|
import hashlib
|
|
from pathlib import Path
|
|
import numpy as np
|
|
from PIL import Image
|
|
|
|
def sha(path):
|
|
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
|
|
|
def read_manifest(path):
|
|
path=Path(path)
|
|
with path.open(newline='') as stream:
|
|
rows=list(csv.DictReader(stream))
|
|
if not rows or not {'id','image','mask','split','group'} <= set(rows[0]):
|
|
raise ValueError('Manifest requires id,image,mask,split,group')
|
|
ids=set(); groups={}; hashes={}
|
|
for r in rows:
|
|
if r['id'] in ids or not r['id'] or '/' in r['id'] or '\\' in r['id'] or r['id'] in ('.','..'):
|
|
raise ValueError('Duplicate/unsafe id')
|
|
ids.add(r['id'])
|
|
if r['split'] not in ('train','dev','cal','test') or not r['group']:
|
|
raise ValueError('Invalid split/group')
|
|
if r['group'] in groups and groups[r['group']]!=r['split']:
|
|
raise ValueError('Scene group crosses splits')
|
|
groups[r['group']]=r['split']
|
|
for k in ('image','mask'):
|
|
r[k]=str((path.parent/r[k]).resolve())
|
|
if not Path(r[k]).is_file(): raise FileNotFoundError(r[k])
|
|
h=sha(r['image'])
|
|
if h in hashes and hashes[h]!=r['split']:
|
|
raise ValueError('Identical image bytes cross splits')
|
|
hashes[h]=r['split']
|
|
return rows
|
|
|
|
def read_pair(row):
|
|
with Image.open(row['image']) as img:
|
|
image=np.asarray(img).copy()
|
|
with Image.open(row['mask']) as img:
|
|
mask=np.asarray(img).copy()
|
|
if image.ndim!=2 or image.dtype!=np.uint8:
|
|
raise ValueError('Prototype requires native-resolution 8-bit grayscale; no implicit conversion')
|
|
if mask.ndim!=2 or mask.shape!=image.shape:
|
|
raise ValueError('Mask shape/format mismatch')
|
|
return image.astype(np.float32)/255., mask>0
|