cv2.demosaicing
Turning a camera's raw Bayer plane into a picture
- src
- result
A camera sensor doesn't see colour. Each photosite sits under one little filter - red, green or blue - arranged in a repeating 2×2 mosaic, which means the raw data off the sensor is a single-channel image where each pixel knows one colour and nothing about the other two. Demosaicing is the reconstruction step that guesses the missing two from the neighbours. cv2.demosaicing is that step, wired up as a node.
Inputs
src is the CFA plane: 8-bit or 16-bit unsigned, one channel. Feed it a colour image and - this is the pack's own behaviour, not OpenCV's - it will quietly run BGR2GRAY on it first, because OpenCV's demosaicing only accepts single-channel input and the pack pre-empts the exception by converting for you. That "helpful" conversion will not turn a photo into a Bayer frame; it just demosaics the luminance, which is not what anyone wants. Check your input is genuinely raw.
src echoes its format on the output, so an IMAGE link in gives you an IMAGE back and you can preview the result directly - one of the friendlier wrappers in this pack for that reason.
code is the part that matters and the default is COLOR_BayerRGGB2RGB. It has to match your sensor's CFA layout, and there are four possibilities (the two green positions and the two colour positions), which is why the pack's dropdown carries the whole family. The suffix on the code tells you the algorithm:
- the plain
...2BGR/...2RGBcodes - bilinear interpolation, fast and the usual starting point; _VNG- variable number of gradients, slower, better on fine texture;_EA- edge-aware, the best-behaved on detail, and the one to try if bilinear gives you colour fringing on high-contrast edges;- the
...2GRAYand...2BGRAvariants if you only want luminance or need an alpha channel; dstCn(default 0) lets you force the output channel count; 0 means "derive it from the code", which is what you want.
Naming caution worth knowing: OpenCV's Bayer labels don't always line up with what a camera vendor or a RAW tool calls the same pattern, and the difference is easy to see - one wrong choice of the four and your colours come out swapped or with a green/magenta cast in the fine detail while the overall image looks plausible. If it looks nearly right but wrong, you picked the wrong pattern, not the wrong algorithm.
Why you'd reach for it here
Realistically: you have CFA data from somewhere - a camera SDK dump, a raw file you decoded yourself, a synthetic sensor test - and you want a normal BGR image out. The pack also ships CV Mosaic Bayer, which does the inverse (takes a colour image and lays it out as a Bayer plane), and the pair makes a decent little sensor-pipeline test rig: mosaic a picture, demosaic it back, look at how much detail the interpolation ate. That's a genuinely instructive ten-minute experiment if you care about what your camera is actually resolving.
For ordinary ComfyUI image work you'll never need it - Load Image and your model's VAE already did this years ago. And note the trade: this is a fast, classic interpolation, not a modern learned demosaicer. Camera vendors and RAW developers use far fancier algorithms (and sometimes neural ones) precisely because this step is where a lot of detail is lost.
Install
Manager → Install Custom Nodes → ComfyUI CV (publisher bmad4ever), or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart ComfyUI. Python ≥ 3.12 and a recent V3-API ComfyUI are required. The contrib headless wheel is the only dependency; nothing here needs a downloaded model. Because all four OpenCV wheels share one site-packages/cv2, installing plain opencv-python over the contrib build silently empties the contrib submodules - python tools/repair_opencv_contrib.py --check and --apply fixes that. The pack is GPL-3.0, a fork of geroldmeisinger/opencv-comfyui, largely LLM-authored, and its author's disclaimer says it isn't production-ready.
Common issues
- Colours are wrong, especially at edges. Pattern mismatch. Cycle the four CFA options;
RGGB,BGGR,GRBG,GBRGare the whole space. - Colour fringing on high-contrast boundaries. Switch from the bilinear code to
_EA. - You fed a normal colour photo and got a slightly odd grayscale back. That's the auto-
BGR2GRAYconversion described above. The node needs a one-channel CFA plane; a three-channel picture isn't one. - A 16-bit CFA plane raises. The node accepts 8- and 16-bit unsigned, but ComfyUI's IMAGE tensors and the pack's
Image → CV Arraypath give you uint8 or float32. Build the array yourself or cast it before the node.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| src | COMFY_MATCHTYPE_V3 | input image: 8-bit unsigned or 16-bit unsigned. The image output(s) echo this input's format. 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. | |
| code | COMBO | COLOR_BayerRGGB2RGB | Color space conversion code (see the description below). |
| dstCnopt | INT | 0-2147483648–2147483647 | number of channels in the destination image; if the parameter is 0, the number of the channels is derived automatically from src and code. The function can do the following transformations: - Demosaicing using bilinear interpolation #COLOR_BayerBG2BGR , #COLOR_BayerGB2BGR , #COLOR_BayerRG2BGR , #COLOR_BayerGR2BGR #COLOR_BayerBG2GRAY , #COLOR_BayerGB2GRAY , #COLOR_BayerRG2GRAY , #COLOR_BayerGR2GRAY - Demosaicing using Variable Number of Gradients. #COLOR_BayerBG2BGR_VNG , #COLOR_BayerGB2BGR_VNG , #COLOR_BayerRG2BGR_VNG , #COLOR_BayerGR2BGR_VNG - Edge-Aware Demosaicing. #COLOR_BayerBG2BGR_EA , #COLOR_BayerGB2BGR_EA , #COLOR_BayerRG2BGR_EA , #COLOR_BayerGR2BGR_EA - Demosaicing with alpha channel #COLOR_BayerBG2BGRA , #COLOR_BayerGB2BGRA , #COLOR_BayerRG2BGRA , #COLOR_BayerGR2BGRA Preset to the OpenCV default (0). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |