Back to the tutorial. Code: code/lw.py, code/copyharness.py, code/stage0_copy.py.
Before painting something Ferrari never painted, copy the nearest thing he did paint, until you can say in one sentence what he's doing. My willow only started working after I copied his hedge. This page is the harness I used to do that.
Ferrari's Living Worlds scenes are public as indexed images: a 256-colour palette plus, for each pixel, an index into it. The master-copy student found that his index map is a form map: each index is a class of surface within a material, and the palette supplies the light. The same index image serves his morning and afternoon versions of a scene. So copy the indices, and the colours come free.
# lw.py
def load(name):
t = open(f"{REF}/{name}.json").read()
t = re.sub(r'([{,])\s*([A-Za-z_]+)\s*:', r'\1"\2":', t).replace("'", '"') # JS object -> JSON
d = json.loads(t)
d["pal"] = np.array(d["colors"], dtype=np.uint8)
d["idx"] = np.array(d["pixels"], dtype=np.int32).reshape(d["height"], d["width"])
return d
V09 = load("V09") # "Deep Forest"
rgb = V09["pal"][V09["idx"]] # the picture
Take a crop and list its indices sorted by luminance, with their shares. For the V09 hedge (native crop x 265–395, y 222–282) the list sorted itself into two short dark-to-light ramps: the lit middle hedge (indices 42, 41, 50, 40, 49) and a bluer far hedge (86, 83, 84, 85). Check by painting each group a flat colour over the crop: groups that are spatially coherent are ramps. For each index I also counted what sits directly below, above, left and right of it (a few lines of np.roll and np.unique); a ramp's steps neighbour each other far more than chance.
# copyharness.py
R, S, table = decompose(idx, pal, [[42, 41, 50, 40, 49], [86, 83, 84, 85]])
R says which ramp owns a pixel, S says how far up that ramp it is, table maps (ramp, step) back to his RGB. Indices outside the ramps snap to the nearest ramp colour.

The copy is allowed two things: which ramp owns each region (a majority vote in a 9-px window) and a blurred light field. Nothing at pixel level.
def sketch(R, S, nramps, maxstep, sigma=2.5, maj=9):
votes = np.stack([ndi.uniform_filter((R == r).astype(float), maj) for r in range(nramps)])
region = votes.argmax(0)
light = ndi.gaussian_filter(S / maxstep, sigma)
return region, light
Then your technique turns (region, light) into a new S, and render(region, S, table) paints it in his colours.
Measure what the marks are. Two measurements taught me most:
Then compare at 3× and at 8× side by side (compare_sheet). The 8× panel is the one that matters.

My C1 copy from a random search that matched his step shares within 3% and his mark sizes. At 8× (bottom) it's camouflage; his has clumps.
My harness computed blurLab (mean ΔE after a 3-px Gaussian) and run lengths. They were useful for catching gross errors, like a copy that was too bright. They were useless for structure: my plain speckle copy of the hedge scored 3.46, and the version with the clump structure that actually looks like his scored 5.7. Use numbers as instruments. Judge at 8× with your eyes, and when a critic names something ("no clump hierarchy"), go back to his 8× crop and find it. It'll be there.
The trick that made me see the clumps was printing the (ramp, step) map as letters, one character per pixel, and reading it. Curving rows of the lit letter are clump caps. It takes three lines:
ch = [['.', ':', 'o', 'O', '#'], [' ', '-', '=', '%']]
for y in range(S.shape[0]):
print(''.join(ch[R[y, x]][S[y, x]] for x in range(S.shape[1])))
Neither of my copies reached "indistinguishable at 8×". C1's darks go flat black between clumps where his carry dim leaves on the lower steps of each ramp; C2's clumps are too even in size. The next thing I'd try is drawing the dim leaves in the dark bands at the bottom two steps, as he does.