Nodes/ComfyUI CV/cv2.xphoto.oilPainting (2/2)
ComfyUI Node

cv2.xphoto.oilPainting (2/2)

The same brush, one fewer knob — here's when to pick it

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
cv2.xphoto.oilPainting (2/2)
  • src
  • result
◄size0►
◄dynRatio0►

If you've found this node by name you've probably already seen cv2.xphoto.oilPainting (1/2) and wondered which of the two you actually clicked. Short answer: this is the three-argument overload, oilPainting(src, size, dynRatio) - no colour-space combo. The two exist because OpenCV ships the function twice in C++ and the pack's ~470 wrappers are generated one-per-overload from the type stubs. Functionally, (2/2) is (1/2) with the colour space fixed.

Why you'd reach for it

Same use as its twin: quantise each neighbourhood to its most common colour and you get flat, painterly regions with wobbly edges, deterministically and on the CPU. Stylise a photo, flatten an image before contour or segment work, or build a repeatable "painted" pass you can apply identically to a whole batch. There is no generative step here at all - which is the appeal if you're in the part of a pipeline where a re-generation is unacceptable.

How it works

For every pixel, take the (2*size+1)² neighbourhood, divide intensities by dynRatio to bin them coarsely, count the bins, and write back the most common one. Bigger size means broader strokes and a much slower run; bigger dynRatio means fewer bins and flatter, poster-like output.

The one difference from (1/2) is which numbers "a colour" is measured in. (1/2) lets you pick - Lab by default, HSV, GRAY, YCrCb, HLS, LUV, XYZ, YUV - and bins the histogram on the first plane. This overload doesn't expose the choice at all, so the colour space is whatever the underlying C++ default resolves to. Which, in practice, means: if you're happy with the default look, use this node and skip a widget; the moment you want to argue about colour space, use (1/2). Everything else - the same neighbourhood, the same binning, the same speed - is identical.

The inputs that matter

  • src - three-channel or single-channel image (CV_8UC3 / CV_8UC1), NPARRAY, IMAGE or MASK.
  • size - neighbourhood half-size. Default 0, which is a 1×1 window and therefore no change to your image. Set 2–7. This is the reported "broken node" almost every time.
  • dynRatio - the quantisation divisor. It divides intensity, so the shipped 0 isn't a usable value; keep it at 1 or above. 1 = subtle, 2–4 = coarse and poster-ish.

Output: result, the same format as src came in as. As with every low-level wrapper in this pack, an IMAGE input returns an NPARRAY, so you'll want CV Array → Image before it rejoins the normal graph.

Install

ComfyUI Manager → ComfyUI CV, or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv

Restart afterwards. opencv-contrib-python-headless~=5.0.0.93 is the dependency that matters - xphoto lives in the contrib wheel only, and the pack's behaviour is curated against that pinned version. Python 3.12+ and a V3-API ComfyUI are both required; older builds can't import the pack at all.

Traps

  • You will not get identical numbers to (1/2) at a non-default code - obviously - but do check both on the same crop once. If the default space suits your image, going with the simpler node makes the graph easier to read later.
  • size = 0 no-ops, dynRatio = 0 is a bad divisor. Both are stub defaults, both bite.
  • Batch behaviour is per image. Feed it a batch and frames are processed one at a time; size at 6+ over fifty frames is a long lunch.
  • Don't chain it with its twin. Two passes of the same quantisation is strictly worse than one pass at a slightly larger size - you just compound the flattening and the Lab round-trip error.
Categoryimage/CV/low-level/xphoto

Inputs (3)

NameTypeDefaultDescription
srcCOMFY_MATCHTYPE_V3Input three-channel or one channel image (either CV_8UC3 or CV_8UC1) 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.
sizeINT0-2147483648–2147483647neighbouring size is 2-size+1
dynRatioINT0-2147483648–2147483647image is divided by dynRatio before histogram processing

Outputs (1)

NameTypeDescription
resultCOMFY_MATCHTYPE_V3Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY.