Nodes/ComfyUI CV/CV Stitch (Advanced)
ComfyUI Node

CV Stitch (Advanced)

Every Panorama Knob OpenCV Hides Behind `cv2.Stitcher`

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
CV Stitch (Advanced)
  • images
  • masks
  • panorama
  • status
  • success
◄featuresorb►
◄matcherbest_of_2_nearest►
◄match_conf-1.00►
◄range_width-1►
◄estimatorhomography►
◄bundle_adjusterray►
◄pano_confidence_thresh1.00►
◄warp_typespherical►
◄wave_correctionauto►
◄registration_resol-1.00►
◄seam_estimation_resol-1.00►
◄compositing_resol-1.00►
◄interpolation_flagsINTER_LINEAR►
◄exposure_compensationgain_blocks►
◄expos_comp_nr_feeds1►
◄expos_comp_nr_filtering2►
◄expos_comp_block_size32►
◄seam_findergc_colorgrad►
◄blend_typemultiband►
◄blend_strength5.0►

cv2.Stitcher is a friendly front door: one call, sane defaults, no opinions required. It's also a black box, and when the black box produces a warped spiral or a seam straight through someone's face, the front door gives you nothing to turn.

This node is the same pipeline with the walls off. It drives cv2.detail directly - feature detection, matching, camera estimation, bundle adjustment, warp type, exposure compensation, seam finding, blending - so every stage that was implicit becomes a widget. The stage order and parameter set deliberately follow OpenCV's own samples/python/stitching_detailed.py, which is the reference implementation most people never find.

You won't touch most of these. You will touch about four.

The four that fix things

warp_type decides the projection. Spherical is the default and right for a wide sweep; plane is the one to reach for when your images are flat and coplanar (document, wall, poster) - spherical on a flat subject is what produces the infamous bow-tie. Cylindrical keeps vertical lines vertical, which matters for architecture. Fisheye/stereographic/mercator exist too.

seam_finder picks how the cut line is chosen. gc_colorgrad (GraphCut on colour + gradient) is the default and generally the best; dp_* (dynamic programming) is faster and less clever; voronoi is crude but very fast; no skips it.

blend_type and blend_strength do the final merge. multiband (Laplacian pyramid) is the quality answer and the default; feather is linear; no is a hard cut. blend_strength (default 5) controls how soft the transition is.

exposure_compensation fixes the brightness mismatch your camera's auto-exposure created between frames - gain_blocks (local block gain) default, gain for a single global gain, channel* variants for colour casts, no to skip.

The rest, briefly

features (ORB fast, SIFT better) and matcher (best_of_2_nearest, the range-limited variant, or the affine one for SCANS-style planar captures) drive matching; match_conf at -1 auto-picks 0.3 for ORB and 0.65 for SIFT. estimator is homography for perspective, affine for flat scenes. bundle_adjuster refines camera parameters - ray default, reproj alternative, no to skip. pano_confidence_thresh excludes images that don't match confidently enough.

wave_correction (auto/horiz/vert/no) kills the drift from hand-held rotation - leave it on auto for panoramas. registration_resol, seam_estimation_resol and compositing_resol are megapixels per stage at -1 = full resolution; lowering them is your memory lever, and only the compositing value affects final sharpness. interpolation_flags picks the warp interpolator. The three expos_comp_* inputs matter only for the channel-based compensators.

And images is the same poly socket as CV Stitch: an IMAGE or LATENT contributes frame 0 only, so for a multi-image stitch use a batched NPARRAY from Image Batch → CV Batch (uint8, in stitch order), with an optional masks batch alongside it.

Outputs are panorama (uint8 BGR), status (an OK or ERR_* label from the pipeline) and success. A failure returns a copy of the first input frame - branch on success.

Install

ComfyUI Manager → search ComfyUI CV (publisher bmad4ever), or:

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

Restart after. Python ≥ 3.12, recent V3-API ComfyUI. The detailed stitching pipeline is core OpenCV, but keep the contrib wheel: a plain opencv-python overwrites the shared site-packages/cv2 and quietly empties the contrib submodules, taking other nodes in the pack with it. tools/repair_opencv_contrib.py --check / --apply.

48_panorama_playground.json wires this and the list variant; 01_install_example_inputs.json copies panorama_A.png / panorama_B.png into your input folder (run it, then reload the page). The stitching runs in a separate process, so it stays interruptible.

Where it bites

Start from the defaults and change one thing at a time. Twenty knobs interacting is a debugging nightmare, and the failure modes are visual: planes fold, seams crawl, exposure bands. If a stitch that worked with cv2.Stitcher goes bad here, the difference is almost always warp_type or the resolutions not being at -1.

Honest framing, from the pack's own README: personal project, heavy LLM assistance, no support promised, workflows built for demonstration rather than production. This node's parameter set is copied from OpenCV's official sample, which makes it the most defensible thing in this corner of the pack - the risk is in the preset values, not the mechanism.

Categoryimage/CV/features

Inputs (22)

NameTypeDefaultDescription
imagesNPARRAY,IMAGE,MASKImage batch to stitch. IMAGE/LATENT: frame 0 only. NPARRAY batch [B,H,W,C]: all B frames are stitched in order. Use 'Image Batch → CV Batch' to convert a ComfyUI IMAGE batch into a batched NPARRAY. 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.
featuresCOMBOorbFeature detector type. ORB is fast and universally available. SIFT is more distinctive but slower.
matcherCOMBObest_of_2_nearestFeature matcher. best_of_2_nearest (default): standard pairwise matching. best_of_2_nearest_range: limits matching to neighbors within range_width. affine_best_of_2_nearest: for affine transformations (SCANS mode).
match_confFLOAT-1.00-1–1Feature match confidence threshold. -1 = auto (0.3 for ORB, 0.65 for SIFT). Higher = fewer, more reliable matches.
range_widthINT-1-1–100Range width for best_of_2_nearest_range matcher. -1 = match against all images. Only used when matcher is best_of_2_nearest_range.
estimatorCOMBOhomographyCamera estimator. homography (default): perspective transforms between images (PANORAMA mode). affine: affine transforms (SCANS mode, planar scenes).
bundle_adjusterCOMBOrayBundle adjustment cost function. ray (default): ray-based error. reproj: reprojection error. affine_partial: partial affine refinement. no: skip bundle adjustment.
pano_confidence_threshFLOAT1.000–10Confidence threshold for feature matching. Images with confidence below this are excluded. Also passed to the bundle adjuster.
warp_typeCOMBOsphericalProjection warp type. spherical (default): good for wide panoramas. plane: no warping (flat scenes). cylindrical: vertical lines stay straight. fisheye/stereographic/mercator: specialized projections.
wave_correctionCOMBOautoWave correction for horizontal/vertical drift. auto (default): auto-detect direction. horiz/vert: force direction. no: disable.
registration_resolFLOAT-1.00-1–100Resolution in megapixels for the registration stage (feature detection + matching). -1 = full resolution.
seam_estimation_resolFLOAT-1.00-1–100Resolution in megapixels for seam estimation and exposure compensation. -1 = full resolution.
compositing_resolFLOAT-1.00-1–100Resolution in megapixels for compositing/warping phase. -1 = full resolution.
interpolation_flagsCOMBOINTER_LINEARInterpolation method for warping. INTER_LINEAR (default) is fast; INTER_CUBIC or INTER_LANCZOS4 are sharper.
exposure_compensationCOMBOgain_blocksExposure compensation method. gain_blocks (default): local block gain. gain: global per-image gain. channel: per-channel gain. channel_blocks: local per-channel gain. no: disable.
expos_comp_nr_feedsINT11–10Number of exposure compensation feeds. Only used for channel / channel_blocks compensators.
expos_comp_nr_filteringINT21–10Number of filtering iterations for exposure compensation gains. Higher = smoother gain maps. Default 2. Only used for channel / channel_blocks compensators.
expos_comp_block_sizeINT321–256Block size (pixels) for block-based exposure compensators (gain_blocks, channel_blocks).
seam_finderCOMBOgc_colorgradSeam finding method. gc_colorgrad (default): GraphCut with color + gradient cost. gc_color: GraphCut, color only. dp_color / dp_colorgrad: dynamic programming. voronoi: Voronoi diagram. no: skip.
blend_typeCOMBOmultibandBlending method. multiband (default): Laplacian pyramid blend (best quality). feather: linear distance blend. no: direct cut.
blend_strengthFLOAT5.00–100Blending strength [0-100]. Higher = softer transition at seams. Default 5.0.
masksoptNPARRAY,MASKOptional coverage mask batch (same B dim as the image batch, or a single mask shared by all frames). 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 (3)

NameTypeDescription
panoramaNPARRAYStitched panorama (uint8 BGR). On failure returns a copy of the first input frame.
statusSTRING'OK' or an error label returned by the detail pipeline.
successBOOLEANTrue when stitching succeeded (status == OK). Use with IfElse to branch on success/failure.