Nodes/ComfyUI CV/cv2.ximgproc.colorMatchTemplate
ComfyUI Node

cv2.ximgproc.colorMatchTemplate

Template matching that doesn't throw away the colour

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.ximgproc.colorMatchTemplate
  • img
  • templ
  • nparray

Template matching is the oldest trick in computer vision: slide a small patch over a big image and score every position by how well they match. cv2.matchTemplate does it on a single channel, which means the standard workflow is "convert to grayscale, hope the thing you're looking for differs in brightness from its surroundings". Often it doesn't. A red lamp on a red wall, a coloured button on a grey panel, a specific logo on packaging - as luminance those are all mush.

cv2.ximgproc.colorMatchTemplate is the version that keeps the channels. It compares the template against every offset using the colour information jointly rather than collapsing to grey first, which is exactly the case grayscale matching fails at.

What you get back

One NPARRAY. And here's the honest part: unlike cv2.matchTemplate, whose response is a single-channel map you can threshold and cv2.minMaxLoc for the best match, ximgproc's colour version works channel-wise, so the response is a multi-channel score map. The pack ships no tooltip text for either input or the return (it's an auto-generated wrapper and OpenCV's doc text for this one is thin), so before building logic on top of it:

cv2.ximgproc.colorMatchTemplate  →  Inspect CV Data

Inspect CV Data reports the shape, dtype and value statistics of whatever you hand it. Run it once, see what the response actually looks like, then decide how you're going to reduce it to a decision - max over channels, mean, threshold per channel. Guessing at the shape is how people end up with a "no match found" bug that's really a channel-index bug.

The size relationship is the same as classic matching: the response is over the valid offsets, so a template of (w, h) against an image of (W, H) gives you roughly (W-w+1) × (H-h+1) positions.

Inputs

  • img - the search image. NPARRAY, IMAGE or MASK, frame 0 of a batch.
  • templ - the template patch. Same accepted types, and it must be smaller than img in both dimensions.

That's the whole node. No method flag, no mask, no normalisation knob - everything is decided inside the function.

Using it in a ComfyUI graph

The realistic shape of this is: a Load Image for the scene, a cropped region (from CV Crop By Bounding Boxes, CV Quad To Rectangle or just an upstream crop) as the template, then this node, then Inspect CV Data while you're developing. Once you trust the response, you reduce it to a scalar and use it as a signal - a threshold comparison, a switch, a score logged alongside a run.

If what you actually want is a match location - "where is the logo" - remember that this node returns the score map only; there's no "best position" output. You'd take the argmax yourself (cv2.reduceArgMax is in the pack and works on a single channel, another reason to know your response's channel count before you start) and then feed that into a drawing or bbox node.

Sibling nodes worth knowing about

  • cv2.matchTemplate - the same idea, single channel, with a proper method flag (TM_CCOEFF_NORMED is the one people mean). Faster, well documented, and the right answer when luminance is enough.
  • cv2.ximgproc.colorMatchTemplate - this node, for when it isn't.
  • CV Match Template Multi-Scale - the curated node for the case where your template might appear at a different size; that's the usual reason plain template matching "doesn't work" on real images.
  • CV Match Features / CV Match Features (Model) - feature-based matching, which is the right tool when the subject can rotate or change perspective, i.e. whenever template matching genuinely can't.

That last distinction is the real one to internalise. Template matching is translation-only. If your target rotates, scales, or tilts, no amount of colour accuracy will save it - you want features, and the pack has those.

Installing it

Comes with ComfyUI CV and needs the contrib build. Manager → search ComfyUI CV, or:

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.

What goes wrong

  • An empty-looking or nonsensical result and no error. Check the shapes first - template bigger than the image is the classic mistake, and its symptom depends on the cv2 version rather than failing cleanly.
  • Everything is a match. Unnormalised scoring without a threshold; look at the actual value distribution in Inspect CV Data before you pick a cutoff.
  • The channels are the wrong way round. If you loaded the template and the scene through different paths, one may be RGB, the other BGR. The pack's CV Array → Image node has a channel_order control and Image → CV Array has a color_format - set both deliberately when the two paths have to agree.
  • Missing ximgproc entirely. That's the shared-site-packages/cv2 race: a non-contrib opencv-python* install leaves the contrib submodules as empty stubs. tools/repair_opencv_contrib.py --check in the pack repo reports it, --apply fixes it.
Categoryimage/CV/low-level/ximgproc

Inputs (2)

NameTypeDefaultDescription
imgNPARRAY,IMAGE,MASK - - - 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.
templNPARRAY,IMAGE,MASK - - - 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.

Outputs (1)

NameTypeDescription
nparrayNPARRAY—