import json,numpy as np
from scipy.interpolate import PchipInterpolator
from scipy.optimize import least_squares
mods=json.load(open('/workspace/scratch/colourmodels.json'));ref=np.array(json.load(open('/workspace/input/chart_reference.json'))['srgb8'])/255
lin=lambda v:np.where(v<=.04045,v/12.92,((v+.055)/1.055)**2.4)
enc=lambda v:np.where(v<=.0031308,12.92*v,1.055*np.maximum(v,0)**(1/2.4)-.055)
for s,m in mods.items():
 obs=np.array(m['observed']);a=lin(obs);t=lin(ref);curves=[];z=[]
 for c in range(3):
  xx=a[18:,c][::-1];yy=t[18:,c][::-1]
  # fit power + offset for useful extrapolation
  fp=least_squares(lambda p:p[0]*xx**p[1]+p[2]-yy,[1,1,0],bounds=([.01,.2,-.05],[20,4,.05]))
  grid=np.linspace(0,1,65536)
  vals=fp.x[0]*grid**fp.x[1]+fp.x[2]
  interp=PchipInterpolator(xx,yy,extrapolate=True)
  vals[(grid>=xx[0])&(grid<=xx[-1])]=interp(grid[(grid>=xx[0])&(grid<=xx[-1])])
  # positive branch below the lowest step is a power anchored on its slope
  slope=interp.derivative()(xx[0]);g=max(.4,min(2.5,slope*xx[0]/yy[0]));lo=grid<xx[0];vals[lo]=yy[0]*(grid[lo]/xx[0])**g
  vals=np.maximum(vals,0);curves.append(vals.tolist())
  z.append(np.interp(a[:,c],grid,vals))
 z=np.array(z).T
 M=np.linalg.lstsq(np.r_[z,np.ones((1,3))*2],np.r_[t,np.ones((1,3))*2],rcond=None)[0]
 err=enc(z@M)-ref
 print(s,round(abs(err).mean()*255,3),round(abs(err).max()*255,3))
 np.savez('/workspace/scratch/'+s+'_curve.npz',curves=np.array(curves),matrix=M,anchor=m['anchor_linear'])
exec(open('/workspace/scratch/colourfit.py').read().split('for s in src:')[0])
from scipy.special import expit
mods=json.load(open('/workspace/scratch/colourmodels.json'))
def enc(v):return np.where(v<=.0031308,12.92*v,1.055*np.maximum(v,0)**(1/2.4)-.055)
for s in ['HH-1041','HH-2203','HH-3315','HH-9395']:
 obs=np.array(mods[s]['observed']);print(s)
 for dom in ['linlin','enclin','linenc','encenc']:
  x=lin(obs) if dom[:3]=='lin' else obs;tar=lin(ref) if dom[3:]=='lin' else ref
  p0=np.r_[np.ones(3),np.linalg.lstsq(x,tar,rcond=None)[0].ravel()]
  def fun(p):
   z=x**p[:3]@p[3:].reshape(3,3)
   return ((enc(z) if dom[3:]=='lin' else z)-ref).ravel()
  ft=least_squares(fun,p0,max_nfev=200,bounds=(np.r_[np.ones(3)*.2,[-10]*9],np.r_[np.ones(3)*5,[10]*9]))
  print(dom,ft.x[:3].round(4),'mean',np.abs(fun(ft.x)).mean()*255,'max',np.max(np.abs(fun(ft.x)))*255)
total 47
drwxr-xr-x 2 root root     0 Oct  7 11:55 .
drwxr-xr-x 3 root root     0 Oct  7 11:54 ..
-rw-r--r-- 1 root root 46284 Oct  7 11:55 checkfonts150.xml
Run experimental bundle that bundles everything
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/workspace/.runtime/tmp/runtime-root'
Traceback (most recent call last):
  File "<string>", line 11, in <module>
  File "<string>", line 10, in <module>
AttributeError: module 'scribus' has no attribute 'quit'
