CV Create CCM Model
You can't fix colour by eye — fit a 3×3 matrix instead
- color_patches
- ccm_model
- ccm_matrix
- loss
What it's for
When the colours are off, most people nudge hue and saturation until it looks right, or re-roll the seed and hope. Both are guesses. The third option has been in film and product photography for decades - shoot a colour chart, measure the error, solve for a matrix - and it's the deterministic half of the colour-correction story in the KB's post-processing notes.
It fits a colour correction model to your camera's rendering of a known chart: a small matrix mapping your sensor's colours onto the chart's real ones. Apply it to every frame from the same camera and lighting and the cast goes away - reproducibly, with a number for how good the fit is.
How it works
Under the hood it's OpenCV's colour-correction model (cv2.ccm). You hand it the patch colours detected on your photo of a chart - [N,1,3] float64, values in 0..1 - plus a reference chart layout, and it optimises a matrix that minimises a colour distance between your patches and the reference values.
Two model shapes:
- CCM_LINEAR - a 3×3 matrix, no offset. Rotates and mixes the channels, which is most of what a colour cast is.
- CCM_AFFINE - 4×3, with an offset term, so it can also correct a shifted black point.
The optimiser works in a linearised space - LINEARIZATION_GAMMA with a gamma of 2.2 is the standard, undoing sRGB's encoding so the arithmetic is happening in light rather than in code values. And the distance metric you pick changes the answer: DISTANCE_CIE2000 is the most perceptually accurate of the options, which is why it's the default. Solving for "least average RGB error" and solving for "least visible error" are different problems; the perceptual metric is the one that looks right afterwards.
The inputs that matter
- color_patches - the detected patches, normally straight from
CV Detect Color Checker. - ccm_type -
CCM_LINEAR(default) orCCM_AFFINE. Start linear. Fewer degrees of freedom, less to overfit, and if the cast is a genuine channel mix it's enough. - color_checker - the reference chart. This must match the physical chart in the photo; a MacBeth reference against a different chart fits a matrix to the wrong target and the loss will tell you.
- linearization and linearization_gamma - leave the gamma method at 2.2 unless you know the space your input is in.
- saturated_lower / saturated_upper - a saturation window for including patches.
saturated_upper = 0disables the upper bound. This is the "throw out the bad patches" control, and it's the one that saves a fit. - distance - the metric. Leave it on CIE2000.
Three outputs. ccm_model goes to CV Apply Color Correction - the one that touches pixels. ccm_matrix is the raw matrix, if you want to look at it or hand it to a raw cv2 call. loss is the fit quality, lower is better, and it's the only honest signal you have.
The repo's 11_color_correction_basic.json walks the whole chain; the CV Color Correct subgraph packages it.
Install
ComfyUI Manager, search ComfyUI CV, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
It comes from OpenCV's colour-checker territory, so the contrib wheel is what you want:
pip install "opencv-contrib-python-headless~=5.0.0.93"
Python ≥ 3.12 and a recent ComfyUI (V3 node API) are required. You'll also need a real chart in the frame - that's a physical object, not a download.
Where people get burned
A single bad patch ruins the fit. One patch sitting in glare, one in shadow, one half-occluded by a finger - and the optimiser bends the whole matrix to accommodate it. Watch the loss output while you play with the saturation window. If loss drops sharply when you raise saturated_lower, you just removed a patch that was lying to you.
The chart type is a claim you're making. Setting color_checker to MacBeth when the physical chart isn't one means the reference values are wrong, so the "correction" is fitting noise. Match it, and note the pack also carries CV GetCCMLoss / CV GetCCMMatrix for inspecting the result separately.
One matrix, one light. A CCM corrects the camera-plus-lighting combination it was fitted on. Fit it in tungsten and use it in daylight and you've made things worse. That's not a limitation of this node, it's what colorimetry is.
It wants [N,1,3] float64 in 0..1 and nothing else. Feed it uint8 values or a different shape and the maths is meaningless rather than erroring nicely.
Missing node? Check the contrib situation. Installing plain opencv-python or opencv-python-headless over a contrib wheel silently empties the contrib submodules, and every contrib-backed node in the pack disappears with it. tools/repair_opencv_contrib.py --check diagnoses it, --apply fixes it.
One caveat from the author's README, and it bites harder here than on the trivial nodes: this pack was written with heavy LLM assistance and isn't recommended for production without validating it against your own cases. For a CCM, validating means trusting loss, not vibes.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| color_patches | NPARRAY | Detected patch colors from 'Detect Color Checker' [N,1,3] float64 in [0,1]. | |
| ccm_type | COMBO | CCM_LINEAR | CCM_LINEAR: 3x3 matrix (no offset). CCM_AFFINE: 4x3 matrix (with offset). |
| color_space | COMBO | COLOR_SPACE_SRGB | Working color space for the correction. |
| distance | COMBO | DISTANCE_CIE2000 | Color distance metric used in optimization. CIE2000 is most perceptually accurate. |
| linearization | COMBO | LINEARIZATION_GAMMA | Linearization method before applying CCM. GAMMA is the standard choice. |
| linearization_gamma | FLOAT | 2.20.1–5 | Gamma value for LINEARIZATION_GAMMA. |
| linearization_degree | INT | 31–10 | Polynomial degree for POLYFIT/LOGPOLYFIT methods. |
| color_checker | COMBO | COLORCHECKER_MACBETH | Reference color checker type (must match chart). |
| saturated_lower | FLOAT | 0.000–1 | Lower saturation threshold for filtering patches. |
| saturated_upper | FLOAT | 0.000–1 | Upper saturation threshold (0 = disabled). |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| ccm_model | CCM_MODEL | Fitted color correction model. |
| ccm_matrix | NPARRAY | The computed 3x3 or 4x3 color correction matrix. |
| loss | FLOAT | Fit quality metric (lower is better). |