cat > /workspace/scratch/initial.py <<'PY'
import numpy as np,cv2,tifffile,json
from PIL import Image,ImageDraw
from pathlib import Path
boxes=json.load(open('/workspace/scratch/chartboxes.json'))
osrc={s:'photos/'+s+'.tif' for s in boxes};osrc['HH-4402']='masters/DSC_4402_master.tif';osrc['HH-6618']='alternates/HH-6618_white.tif'
Path('/workspace/scratch/diffs').mkdir(exist_ok=True)
for s,src in osrc.items():
 a=tifffile.imread('/workspace/input/'+src).astype('float32')/65535;b=tifffile.imread('/workspace/input/charts/'+s+'_chart.tif').astype('float32')/65535
 # diff after estimated multiplicative shadow removal, using chroma and absolute distance
 aa=cv2.GaussianBlur(a,(0,0),.7);bb=cv2.GaussianBlur(b,(0,0),.7)
 diff=np.linalg.norm(aa-bb,axis=2)
 ratio=(aa*bb).sum(2)/(bb*bb).sum(2)
 chroma=np.linalg.norm(aa-bb*np.minimum(ratio,1)[:,:,None],axis=2)
 # display diff mask plus chart outlines
 mask=(chroma>.035).astype('uint8')*255
 x0,y0,x1,y1=boxes[s];cv2.rectangle(mask,(x0-8,y0-8),(x1+8,y1+8),128,-1)
 Image.fromarray(mask).resize((600,400)).save('/workspace/scratch/diffs/'+s+'.png')
 # composite thumbnail with coordinate grid
 vis=(a*255).astype('uint8');
 for x in range(0,2400,100): cv2.line(vis,(x,0),(x,1600),(100,140,180),1)
 for y in range(0,1600,100):cv2.line(vis,(0,y),(2400,y),(100,140,180),1)
 Image.fromarray(vis).resize((1200,800)).save('/workspace/scratch/'+s+'_grid.jpg')
out=Image.new('RGB',(1600,6*295),'#dddddd');d=ImageDraw.Draw(out)
for i,s in enumerate(osrc):
 im=Image.open('/workspace/scratch/diffs/'+s+'.png').resize((400,267));x=(i%4)*400;y=(i//4)*295;out.paste(im,(x,y));d.text((x+5,y+267),s,fill='black')
out.save('/workspace/scratch/diffcontact.png')
json.dump(osrc,open('/workspace/scratch/sources.json','w'),indent=2)
PY
OPENBLAS_NUM_THREADS=1 python /workspace/scratch/initial.py