Color Correction

Color correction is two separate things in Imaginary Arts. A grade changes the colors: brightness, contrast, saturation, warmth, the lift of the shadows. A film look changes the texture: softness, grain, vignette, the slight color fringing of a cheap lens. They are independent, each has presets, and each can be dialed in by hand.

Applying a look

Both are added to the timeline for an interval. [0, None] means the whole video.

from imaginaryarts import Grade, FilmLook

video.add_grade(Grade.VintageFade(), interval=[0, None])
video.add_film_look(FilmLook.LoFi(), interval=[0, None])

Because they take an interval, a look can also change partway through: a warm grade over the flashback and a neutral one over the rest, or grain only on the archival section.

video.add_grade(Grade.Warm(), interval=[0, 12000])
video.add_grade(Grade.Neutral(), interval=[12000, None])

interval=None is the same as [0, None]. If nothing is added, the video is rendered without a grade or a film look. Two grades, or two film looks, may not overlap in time; where one interval ends and the next begins, the look switches on that frame, so put the boundary on a cut.

Grade

Presets

PresetLook
Grade.Neutral()No change.
Grade.VintageFade()Lifted blacks, soft whites, a touch more contrast and saturation, warm highlights against violet shadows. The faded-photograph look.
Grade.Warm()Slightly warmer midtones and highlights. Flattering on skin and interiors.
Grade.Cool()Cool shadows and highlights. Clinical, nocturnal.
Grade.Noir()Fully desaturated with strong contrast.
Grade.Vivid()Saturation and contrast pushed up. Bright, punchy, social-video color.

Your own grade

The simple constructor takes normalized knobs where 0 means "leave it alone". Positive values push in the direction the name suggests, negative values the other way, from -1 to 1; fade runs from 0 to 1.

Grade(
    brightness=0,     # -1 darker .. +1 brighter
    contrast=0.2,     # -1 flatter .. +1 punchier
    saturation=-0.1,  # -1 grayscale .. +1 vivid
    fade=0.25,        # 0 none .. 1 fully lifted blacks and dimmed whites
    temperature=0.3,  # -1 cooler .. +1 warmer
    tint=0,           # -1 green .. +1 magenta
    split=0.2,        # 0 .. 1 warm highlights against cool shadows
)

For full control there is Grade.advanced(...), which sets the underlying values directly: saturation, contrast, brightness, gamma, black_lift, white_point, and RGB offsets for shadows, midtones and highlights. Here 1.0 is neutral for the multipliers and 0.0 for the offsets, so the scales differ from the simple constructor. Start from a preset and change one thing with with_:

Grade.VintageFade().with_(black_lift=0.08)

Film look

Presets

PresetLook
FilmLook.Neutral()No change.
FilmLook.LoFi()Slight softening, fine grain, a clear vignette and a little chromatic aberration. The house look for generated imagery; it hides the too-clean edges of AI images.
FilmLook.Grainy()No softening, heavy grain, a light vignette.
FilmLook.Dreamy()Strong softening, light grain, a deep vignette.
FilmLook.Vintage()Softening with a lower internal resolution, heavy grain, deep vignette and pronounced color fringing. Old tape.
FilmLook.Clean()Only a faint vignette. For footage that should stay sharp.

Your own film look

The simple constructor takes four amounts from 0 to 1:

FilmLook(
    soften=0.3,     # blur
    grain=0.2,      # film grain
    vignette=0.5,   # darkened corners
    chroma=0.1,     # color fringing at the edges
)

FilmLook.advanced(...) exposes the underlying values (soften_sigma, soften_resolution, grain_amount, grain_downscale, grain_temporal, vignette, chroma_shift), and with_ changes one of them on a preset:

FilmLook.LoFi().with_(grain_amount=30)

The effects always run in the same order, soften then grain then vignette and fringing, and any effect at zero is skipped entirely, so FilmLook.Neutral() leaves the picture untouched.

Which to use

A grade is applied before captions are drawn, so the text keeps its exact colors. A film look is applied over everything at the very end, captions included, which is what makes text feel like part of the picture rather than a sticker on it. For generated imagery, Grade.VintageFade() plus FilmLook.LoFi() is the combination the library was tuned around. For real footage, start with Grade.Neutral() and FilmLook.Clean() and add from there.