Nodes/ComfyUI CV/cv2.copyMakeBorder
ComfyUI Node

cv2.copyMakeBorder

The honest way to pad an image inside the graph

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.copyMakeBorder
  • src
  • result
◄top0►
◄bottom0►
◄left0►
◄right0►
◄borderTypeBORDER_DEFAULT►
◄value►

Sooner or later you need a bigger image without scaling anything: pad a frame to a multiple of 32 so an ONNX graph will accept it, letterbox to a canvas before a paste, or grow a texture by a few pixels so it tiles. cv2.copyMakeBorder is the primitive for all three, and this pack exposes it as the node cv2.copyMakeBorder (category image/CV/low-level/cv2 C).

It's one of roughly 470 auto-generated cv2.* wrappers in bmad4ever's ComfyUI CV pack - a one-person project, forked from geroldmeisinger's opencv-comfyui, rebuilt on ComfyUI's V3 node API. The README is unusually blunt about it: much of the code was written with LLM assistance, updates aren't planned, and it should not go into production without your own review. Treat it as a toolbox of small, correct, deterministic ops - which is exactly what the classic post-processing layer argues you should reach for instead of burning a diffusion pass on work a lookup table does perfectly.

How it works

OpenCV doesn't stretch the image; for every output pixel that falls outside the source rectangle it asks borderInterpolate which source pixel to sample. That rule is the whole node, and the dropdown is the rule:

  • BORDER_CONSTANT - fill the new area with value (black by default). The letterbox/pad-to-canvas option.
  • BORDER_REPLICATE - clamp to the edge pixel. Cheap, no invented content, visible streaks on gradients.
  • BORDER_REFLECT_101 - mirror excluding the edge row. This is what BORDER_DEFAULT means in cv2, and it's what filters use so they don't overshoot at the frame line.
  • BORDER_REFLECT - mirror including the edge, so the edge pixel appears twice.
  • BORDER_WRAP - wrap around from the opposite side. This is the manual cousin of the circular-padding trick that makes a texture tileable, and a deterministic alternative to re-rolling a model with "tiling" switched on.

This is a type-preserving node: it echoes its input's format, so an IMAGE link comes back IMAGE and a MASK comes back MASK. No Image → CV Array bridge on either side, which is the main reason it's more pleasant here than in raw cv2.

The inputs and outputs that matter

src is the image (IMAGE, MASK or NPARRAY - a wire only, no widget). You actually set four integers, top, bottom, left and right, and they're independent on purpose: 64 down, 0 elsewhere is a perfectly normal call. borderType is the dropdown above.

The optional value is a STRING and only means anything when borderType is BORDER_CONSTANT. It's parsed as a Python literal, so (0, 255, 0) is BGR green and (0, 255, 0, 64) adds an alpha component; a bare number broadcasts to every component, so 255 means white. Leave it blank for OpenCV's default. One output, result, carrying the padded array in whatever format arrived.

Installing it

The pack installs the usual way: ComfyUI Manager → search the pack title (ComfyUI CV) → install → restart ComfyUI. By hand:

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

It needs Python ≥ 3.12 and a recent ComfyUI built on the V3 node API. One dependency, pinned:

pip install "opencv-contrib-python-headless~=5.0.0.93"

The contrib part is not optional. All four OpenCV wheels share one site-packages/cv2, so installing plain opencv-python over the contrib wheel silently empties the contrib submodules and those nodes vanish on the next restart. The pack ships tools/repair_opencv_contrib.py - --check to diagnose, --apply to fix.

Common issues and troubleshooting

"value" seems to do nothing. It only applies to BORDER_CONSTANT. On any other border type OpenCV ignores it and you're looking at the wrong tool.

A ValueError about a Python literal. value is parsed, not matched - green or #00ff00 raises "not a valid Python literal". Write the tuple, or a bare number.

Everything downstream got bigger. That's the point, but it bites: the padded result is the new image, and any node after it sees src + left + right by src + top + bottom. Pad late, keep the numbers in variables, or use CV Slice Array to crop the padding back off after a warping/round-tripping step it was protecting.

Your numpy/opencv stack broke something else. The pinned wheel drags in numpy 2.x, and that is the classic collision in this ecosystem - insightface 0.7.3 needs numpy 1.x, opencv needs 2.x, and the thread that keeps coming up is a user 36 hours deep in exactly this. If an InstantID/IPAdapter FaceID node quietly stopped working after installing anything opencv-shaped, suspect this before you suspect the pack.

Categoryimage/CV/low-level/cv2 C

Inputs (7)

NameTypeDefaultDescription
srcCOMFY_MATCHTYPE_V3Source image. The image output(s) echo this input's format. A LATENT link is processed in latent space: frame 0 becomes a float32 [H,W,C] array (any channel count), values untouched. Arithmetic ops (add, multiply, etc.) also accept a full LATENT batch ({samples: [B,C,H,W]}) — the whole batch flows through when both inputs have the same batch size. 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.
topINT0-2147483648–2147483647the top pixels
bottomINT0-2147483648–2147483647the bottom pixels
leftINT0-2147483648–2147483647the left pixels
rightINT0-2147483648–2147483647Parameter specifying how many pixels in each direction from the source image rectangle to extrapolate. For example, top=1, bottom=1, left=1, right=1 mean that 1 pixel-wide border needs to be built.
borderTypeCOMBOBORDER_DEFAULTBorder type. See borderInterpolate for details.
valueoptSTRINGBorder value if borderType==BORDER_CONSTANT . cv2 Scalar as a literal, e.g. "(0, 255, 0)" (BGR) or "(0, 255, 0, 64)" (BGRA). A bare number broadcasts to every component, so "255" means (255, 255, 255, 255). Components past the target's channel count are ignored by OpenCV. Leave blank for the OpenCV default.

Outputs (1)

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