cat > /workspace/scratch/warmfur.py <<'PY'
import cv2,numpy as np,json,tifffile
from scipy import ndimage as ndi
from PIL import Image
for s in ['HH-9328','HH-9340']:
 p='/workspace/scratch/finalmasks/'+s+'.png';old=cv2.imread(p,0);m=old>127
 ox,oy=json.load(open('/workspace/scratch/detailboxes.json'))[s][:2]
 a=(tifffile.imread('/workspace/input/photos/'+s+'.tif').astype('float32')/65535)**2.2
 fg=ndi.distance_transform_edt(m)>13;bg=ndi.distance_transform_edt(~m)>14
 _,fi=ndi.distance_transform_edt(~fg,return_indices=True);_,bi=ndi.distance_transform_edt(~bg,return_indices=True)
 F=cv2.GaussianBlur(a,(5,5),1)[fi[0],fi[1]];B=cv2.GaussianBlur(a,(7,7),2)[bi[0],bi[1]]
 D=F-B*((F*B).sum(2)/((B*B).sum(2)+1e-8))[:,:,None]
 al=np.clip((a*D).sum(2)/((D*D).sum(2)+1e-7),0,1);al[fg]=1;al[bg]=0;al[al<.04]=0
 # Refine only the neutral floor against the warm pile, not the dark sofa behind the top.
 start=oy+1050
 for y in range(start,start+30):
  f=(y-start)/30;old[y]=np.rint(old[y]*(1-f)+al[y]*255*f).astype('uint8')
 old[start+30:]=np.rint(al[start+30:]*255).astype('uint8');cv2.imwrite(p,old)
 im=Image.open('/workspace/input/photos/'+s+'.tif');o=Image.new('RGB',im.size,(130,72,132));o.paste(im,(0,0),Image.fromarray(old));o.crop(json.load(open('/workspace/scratch/detailboxes.json'))[s]).save('/workspace/scratch/check_'+s+'.png')
PY
OPENBLAS_NUM_THREADS=1 python /workspace/scratch/warmfur.py