{
 "version": "ultimate-v13",
 "skus": [
  {
   "sku": "HH-1041",
   "name": "Wharf storm lantern",
   "price": "£42",
   "description": "Hand-finished in antiqued brass, the Wharf lantern takes a standard oil burner or our battery candle insert. The smoked glass globe softens the flame, and the wire guards keep it steady when you carry it by the swing handle. Hang it from a hook on the porch or set it on a table for evenings outside. Wipe the glass with a dry cloth only.",
   "delivered_frame": "photos/HH-1041.tif",
   "chart_frame": "charts/HH-1041_chart.tif"
  },
  {
   "sku": "HH-1206",
   "name": "Cumulus round faux-fur pouf",
   "price": "£85",
   "description": "Long, cream faux fur covers the Cumulus pouf, a drum-shaped seat with softly rounded edges for a bedroom, a dressing table or a reading corner. The firm foam core keeps its shape, and the cover zips off for a gentle hand wash. Brush the pile with a wide comb to keep it full.",
   "delivered_frame": "photos/HH-1206.tif",
   "chart_frame": "charts/HH-1206_chart.tif"
  },
  {
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)
exec(open('/workspace/scratch/testseg.py').read().split('for s,src in sources.items():')[0])
from scipy.ndimage import binary_fill_holes
for s in ['HH-1206','HH-2203','HH-2342','HH-5593','HH-7158','HH-8285','HH-9328','HH-9340','HH-9374']:
 a=tifffile.imread('/workspace/input/'+sources[s]).astype('float32')/65535;b=tifffile.imread('/workspace/input/charts/'+s+'_chart.tif').astype('float32')/65535
 aa=cv2.GaussianBlur(a,(0,0),.5);bb=cv2.GaussianBlur(b,(0,0),.5);d=(aa-bb).mean(2)
 mask=(d>.012).astype('uint8');x0,y0,x1,y1=limits[s];reg=np.zeros(mask.shape,'uint8');reg[y0:y1,x0:x1]=1;mask*=reg
 cx0,cy0,cx1,cy1=boxes[s];mask[cy0-15:cy1+15,cx0-15:cx1+15]=1
 n,lab,stats,ctr=cv2.connectedComponentsWithStats(mask,8);mask=(lab==1+np.argmax(stats[1:,4])).astype('uint8');mask=binary_fill_holes(mask).astype('uint8')
 cv2.imwrite('/workspace/scratch/seg/'+s+'_pos.png',mask*255)
 vis=a*.6+np.array([0,0.9,0.8])*mask[:,:,None]*.4
 Image.fromarray((np.clip(vis,0,1)*255).astype('uint8')).resize((1200,800)).save('/workspace/scratch/seg/'+s+'_pos.jpg')
