Headless Mode
Free · open source

pycube-lut

Read and apply Adobe .cube 3D LUTs, HALD CLUTs and 1D tone curves to NumPy images

Shipped

Loads any Adobe .cube 3D LUT, HALD CLUT PNG, or 1D tone curve and applies it to a NumPy image in one call — pure NumPy, no ffmpeg process, no OpenColorIO, no GPU.

Why a 3D lookup table

A global knob — saturation, an S-curve, a black point — moves every hue in an image the same way. A real film stock’s look is hue-selective: it does one thing to skin and a different thing to foliage, which needs a full three-dimensional lookup. Video tools reach .cube files through ffmpeg’s lut3d filter; for a single still image already in memory, spawning an encoder just to grade it is the wrong tool. pycube-lut is the still-image equivalent — a small NumPy module that parses the table and trilinearly interpolates the pixels through it.


One call, three input shapes

You haveload_cube gives you
Adobe .cube with LUT_3D_SIZEthe table as-is
HALD CLUT PNG (a square grid image)the same table, read from pixels
.cube with LUT_1D_SIZE (three tone curves)an equivalent separable 3D cube

apply_cube(image, cube, strength) takes it from there. strength is opacity in [0, 1], and the output dtype always matches the input — a 16-bit master stays 16-bit out, so a look laid over it does not throw away its headroom.


Honest limits

Trilinear interpolation only — Resolve, Photoshop and ffmpeg’s own lut3d default to tetrahedral, so expect small deviations on steep LUTs. 8-bit and 16-bit integer images only, no float and no colour management: a LUT authored for log footage needs log input, and nothing here checks that for you.


Requirements

Python 3.11+. NumPy only for .cube and 1D-curve files; reading a HALD CLUT PNG additionally needs Pillow (the package’s hald extra pulls it in).


Documentation

pycube-lut’s documentation lives in its repository, next to the code it describes — the README is the manual.

← All software