AM Color Correct
Six knobs that fix the color before you export
- image
- video
- image
- video
Every generated image eventually needs a color pass that isn't the diffusion model's idea of a color pass. That's what AM Color Correct is: a Nuke ColorCorrect-style grade rebuilt in pure torch, where the whole thing is six sliders - saturation, contrast, gamma, gain, offset, and hue rotation - and nothing else. No blackpoint/whitepoint algebra, no per-channel fiddling. If you want "make this pop a little before I write it out," this is the node you grab.
It's part of the comfyui-am-vfx-tools pack (the "AM VFX Tools" category), a 13-node VFX I/O and color toolkit by Adrian Meyer that's the public slice of an internal studio pipeline. The color nodes all share the same philosophy: Nuke-style math, float-friendly, alpha-preserving.
How it works
The math is per-pixel and deterministic, in a fixed order:
- offset (additive, applied first)
- gain (multiply)
- gamma - a sign-preserving
pow(x, 1/gamma) - contrast - around a pivot of 0.18, scene-linear mid-gray
- saturation - around Rec.709 luma
- hue - rotation around the gray axis
The pipeline is straight out of Nuke's ColorCorrect, and the two details worth knowing: contrast pivots at 0.18 because the pack assumes you're working in scene-linear (more on the trap below), and gamma uses a sign-preserving pow so negative values - which happen constantly with a negative offset on a linear plate - don't turn into NaN.
The inputs that matter
Honestly, two of the six. The tooltips are the author's own words, and they're good:
saturation- 0 = grayscale, 1 = identity, > 1 boosts. Around Rec.709 luma.contrast- 0 = flat mid-gray, 1 = identity, > 1 increases. Pivots at 0.18.
The rest are standard: gamma > 1 brightens midtones, gain is a multiply applied before gamma, offset is the additive kick applied first, and hue_rotation spins the hue wheel in degrees (±180 = full loop). All default to identity, so the node is a no-op until you touch something - safe to drop in a graph.
It takes an optional image batch and an optional video (if you wire video, it returns a lazy per-frame wrapper and the image input is ignored). Outputs are image - same shape and channels as the input - and video. Alpha passes through untouched either way.
Installing it
Same story as every node in this pack - install the pack once, get all 13:
cd ComfyUI/custom_nodes
git clone https://github.com/am-pipeline-prod/comfyui-am-vfx-tools.git
cd comfyui-am-vfx-tools
pip install -r requirements.txt
Restart ComfyUI. Or search comfyui-am-vfx-tools in ComfyUI Manager. The heavy hitters in requirements.txt are OpenImageIO, OpenColorIO ≥ 2.5, PyAV, and OpenCV headless - those are the actual dependencies and they don't auto-install, so the pip install step is not optional.
Where people get burned
The contrast pivot is 0.18, which only makes sense in linear light. If you feed it an sRGB image straight out of a VAE and push contrast, it behaves differently than the "brightness slider" you're used to - you get a real lift/crush around mid-gray instead of a gamma-style bend. That's correct behavior for a color-managed pipeline; it just surprises people who expect a dumb contrast knob. The fix is either to work through the pack's OCIO nodes (or AM Read Image's colorspace conversion) so you're actually in linear, or to use this on display-referred images and just eyeball it - for quick LDR fixes, eyeballing works fine.
One more: it's torch, per-pixel, and fast, but it doesn't invent detail. If your color is off because the image is broken, a grade won't fix it - reach for img2img or an actual color match instead. This node is for when the pixels are right and just need to be pointed in the right direction.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| saturation | FLOAT | 1.000 | Saturation multiplier around Rec.709 luma. 0 = grayscale, 1 = identity, > 1 boosts saturation. |
| contrast | FLOAT | 1.000 | Contrast around scene-linear mid-gray (pivot 0.18). 0 = flat mid-gray, 1 = identity, > 1 increases contrast. |
| gamma | FLOAT | 1.000 | Gamma (sign-preserving `pow(x, 1/gamma)`). > 1 brightens midtones, < 1 darkens, 1 = identity. |
| gain | FLOAT | 1.000 | Multiplicative gain — applied after `offset`, before `gamma`. 1 = identity. |
| offset | FLOAT | 0.000 | Additive offset — applied first (before gain / gamma / contrast / saturation / hue). 0 = identity. |
| hue_rotation | FLOAT | 0.0-180–180 | Hue rotation in degrees around the gray axis [1,1,1]. 0 = identity; ±180 spans the full hue wheel (equivalent on the loop). Applied last. |
| imageopt | IMAGE | Image batch to color-correct. | |
| videoopt | VIDEO | Optional VIDEO input. When wired, returns a lazy `ColorCorrectedVideo` wrapper applying the correction per-frame on consumption — no IMAGE materialisation here. Alpha (when present) passes through untouched. `image` is ignored when `video` is wired. See invariant 28. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | Corrected image batch (same shape and channels as the input). |
| video | VIDEO | Lazy VIDEO output — emits a `ColorCorrectedVideo` wrapper when `video` is wired, else a zero-copy `VideoFromComponents` around the IMAGE batch. None when no input is wired. |