looking at my code i think i guess the python would look like
def density_dir_model_hanatos(raw, e, dc, M):
M = M*0.1 # reduced inhibition matrix for matching roughly the models
e = np.vstack((e,e,e)) # log exposure
# compute couplers:
c = np.einsum('ck, cm->mk', raw, M)
# apply couplers to raw exposure:
raw = raw - c;
# now apply our fake D_0(.) which is assuming monochromatic (so we make it mono and apply it 3x)
e_corr = np.zeros_like(raw)
e_corr[0,:] = np.einsum('ck, cm->mk', np.vstack((raw[0,:],raw[0,:],raw[0,:])), np.linalg.inv(np.eye(3)-M))[0,:]
e_corr[1,:] = np.einsum('ck, cm->mk', np.vstack((raw[1,:],raw[1,:],raw[1,:])), np.linalg.inv(np.eye(3)-M))[1,:]
e_corr[2,:] = np.einsum('ck, cm->mk', np.vstack((raw[2,:],raw[2,:],raw[2,:])), np.linalg.inv(np.eye(3)-M))[2,:]
# now the only time we evaluate the D lut:
d = interp_with_curves(e_corr, e, dc)
return d
which is not really better than your plot:
the idea is that i only have to call the density lut once and can do the rest analytically. also it bugs me that we can’t reverse the measured density curves to “actual” curves that would physically happen in the film before couplers. i tried to run some fixed point iteration as an offline preprocess but the results looked horrible. i might have a bug because my python is abysmal, but also it might just not work like this. results match the uncontrolled colour shifts you described earlier when not respecting the density curves as data.