Nodes/ComfyUI CV/cv2.correctChromaticAberration
ComfyUI Node

cv2.correctChromaticAberration

Fixing colour fringing, if you have a calibration

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.correctChromaticAberration
  • input_image
  • coefficients
  • image_size
  • nparray
◄calib_degree0►
◄bayer_patternCOLOR_BayerRGGB2BGR►

Lateral chromatic aberration is the lens problem where red and blue focus at slightly different positions, so high-contrast edges in your render pick up a red or cyan fringe. It's also a post-processing trick people add on purpose to make an image read as camera-captured. cv2.correctChromaticAberration is the removing half: given a per-channel polynomial displacement model for your lens, it resamples the channels back into alignment.

It's a cv2 5.0 addition, exposed as the node cv2.correctChromaticAberration in bmad4ever's ComfyUI CV pack (category image/CV/low-level/cv2 C). Because the registry is generated against your installed OpenCV, this node only appears on a build that has the function - which in practice means the pinned opencv-contrib-python-headless~=5.0.0.93 the README curates against. On an OpenCV 4.x install, the node simply won't be there.

How it works

The model is per-channel radial displacement, expressed as a polynomial rather than a single offset: red and blue are warped by slightly different amounts depending on distance from the optical centre, green is the reference. The node hands cv2 the coefficient model, the image size the model was calibrated for, and the polynomial degree, and cv2 resamples accordingly. If the input is a single-channel raw Bayer frame, cv2 demosaics it first using the bayer_pattern you pick, then corrects - that's the only reason that dropdown exists.

This is the deterministic repair for a specific optical defect, not a general "fix fringes" filter. Applied with the wrong calibration it will add fringing, which is a very convincing demo of why calibrations are camera- and lens-specific.

The inputs and outputs that matter

input_image is the image to correct (its tooltip says BGR; the pack converts ComfyUI's RGB IMAGE to BGR for every cv2 call, so a normal image wire is fine).

coefficients is the part that trips people up: an NPARRAY holding the coefficient model, not a file path and not a number. OpenCV's companion function loadChromaticAberrationParams documents it as a 4×N CV_32F matrix, where N determines the polynomial degree. It comes from a calibration run over photos of a target - OpenCV's own tooling lives in the upstream apps/chromatic-aberration-calibration/ script mentioned in the pack's curated node description. There's no node wrapping the loader in this pack, so the raw-node path means producing that matrix yourself and typing it in via Parse Matrix (cast it to float32 with CV Cast Array if it arrives as float64).

image_size is a CV_TUPLE - the size of the images the model was calibrated for, not necessarily the size of the image you're feeding in. calib_degree is the polynomial degree of that same model (degree 1 for a constant-shift calibration; higher for real lenses). If degree and matrix disagree, expect an assertion, not a gentle failure.

The single output is nparray - an NPARRAY, not an IMAGE. CV Array → Image converts it back if you want to save or preview it, and cv2.resize (or CV Array → Image plus core resize) is what you need if your image size and image_size don't match. Which is exactly the work the curated node already does.

The easier route in the same pack

Unless you're generating the coefficient matrix yourself, use CV Chromatic Aberration Correction instead. It takes an IMAGE and reads a calibration .yaml/.xml from a dropdown (input/calib/), loads the model, resizes to the calibration size, calls this same function, resizes back, and emits an IMAGE. Its siblings are Create CA Calibration, which synthesizes a degree-1 calibration file (+15 red, −10 blue in the shipped example) so you can test the round trip, and CV Apply Chromatic Aberration, which simulates the defect by shifting R and B with polynomial displacement maps. The pack's 14_chromatic_aberration.json workflow wires simulation → correction → cv2.absdiff against the original, which is a genuinely good way to see what the correction can and can't recover (answer: the edges, and only approximately, because interpolation).

Installing it

Manager → search the pack title (ComfyUI CV) → install → restart. Manual:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Python ≥ 3.12 and a V3-API ComfyUI. The version pin matters more here than elsewhere in the pack: this function is new, so a stray old OpenCV wheel is the difference between the node existing and not existing. If nodes keep disappearing, python -c "import cv2; print(cv2.__file__, cv2.__version__)" answers "which cv2 am I actually running" in one line, and the pack's CV Build Information node prints the same story with paths redacted.

Common issues and troubleshooting

The node isn't in the list. Your OpenCV doesn't have the function. Check cv2.__version__ - the pack is curated against 5.0.0.93 and needs the contrib wheel.

"(-215) assertion failed" from inside cv2. Usually calib_degree disagreeing with the number of columns in coefficients, or a coefficient array that isn't CV_32F.

Fringing gets worse, or the image shifts. The image_size doesn't match the calibration the coefficients were fitted at. Feed the calibration's own size - the curated node resizes for you precisely because forgetting this is the standard mistake.

Fringes survive in the corners. A degree-1 model with a constant displacement can only correct so much; real lenses need a higher-degree fit. And residual fringing after correction is normal - the resampling can't invent the sub-pixel information the original sampling threw away. Judge the result at 100%, on the edges: lateral CA barely shows at viewing size, which is the same trap people fall into with every subtle post-processing pass.

Categoryimage/CV/low-level/cv2 C

Inputs (5)

NameTypeDefaultDescription
input_imageNPARRAY,IMAGE,MASKInput BGR image to correct Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size.
coefficientsNPARRAYCoefficient model A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
image_sizeCV_TUPLE0,0Size of images for the calibration coefficient model One value with 2 components (w, h) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place.
calib_degreeINT0-2147483648–2147483647Degree of the calibration coefficient model
bayer_patternoptCOMBOCOLOR_BayerRGGB2BGRBayer pattern code (e.g. cv::COLOR_BayerBG2BGR) used for demosaicing when @p input_image has one channel; ignored otherwise.

Outputs (1)

NameTypeDescription
nparrayNPARRAY—