ComfyUI Node

Mask Concat

Left-right or top-bottom, no maths

By live1617·Created 29 days ago·Updated 8 days ago· 4
Mask Concat
  • mask1
  • mask2
  • MASK
◄match_sizefalse►
◄directionleft-right►

Masks in ComfyUI have almost no basic arithmetic. Image nodes can paste, composite and blend; mask nodes give you invert, threshold, blur, and then you're into the pack ecosystem for anything else. Joining two masks into one is a genuinely common need - half a face from one region, half from another; a left mask and a right mask for a panorama - and 遮罩拼接 (QG_MaskConcat) is the small purpose-built answer.

How it works

Two MASK inputs, mask1 and mask2, a direction, and a size switch. direction is 左右 (horizontal) or 上下 (vertical). The node builds a canvas big enough for both and drops each mask into its corner:

  • 左右: canvas height is the taller of the two, width is the sum. mask1 sits top-left, mask2 immediately to its right.
  • 上下: canvas width is the wider, height is the sum. mask1 sits top-left, mask2 directly beneath.

The leftover area in the shorter dimension stays black - which for a mask means "not selected", not "unknown". That's usually what you want: the union of two regions with dead space where neither reached.

match_size (off by default) changes the arithmetic. On, it compares the area of the two masks and stretches the smaller one up to the larger one's dimensions with a bilinear resize, so the two halves line up as equal blocks. Stretched, not letterboxed - a small mask blown up to a big one's size will soften and distort. Off, each keeps its own dimensions and the canvas accommodates both. On is right for "two halves of the same face"; off is right for "two different crops I want in one mask tensor".

Output is a standard (1, H, W) mask, so anything downstream that expects a MASK reads the dimensions correctly rather than discovering a stray batch axis. The node normalises inputs too: a 4-D mask gets max-reduced across channels, a 2-D mask gets a batch axis, so the shapes coming in don't have to be identical.

Inputs and outputs

  • mask1 (required, MASK) - left / top piece.
  • mask2 (required, MASK) - right / bottom piece.
  • match_size (required, boolean, default off) - stretch the smaller mask to the larger one's size.
  • direction (required, enum: 左右 / 上下) - join axis.
  • Output MASK - the joined mask, (1, H, W).

Where this fits: building a single inpaint mask from two detection passes, or from two hand-drawn regions you made in separate MaskEditor sessions. It's a plumbing node - it exists to stop you rebuilding the same composed mask by hand every run.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/live1617/ComfyUI-QG-tools

Restart ComfyUI fully afterwards - a page refresh is not enough for backend nodes. The console should report [QG-tools] v0.9.2 加载完成 | 节点数 24. Manager users can search ComfyUI-QG-Tools where the registry entry is live. Nothing to install with pip: the pack ships a comments-only requirements file precisely so Manager has no pip step to run.

Ported from ComfyUI_Muye (MIT); the pack keeps the upstream licences in licenses/. Search mask concat, merge masks or 遮罩拼接.

Where people get burned

Corner alignment, not centre alignment. Masks are placed at their canvas corners. Two masks of different heights joined left-right end up top-aligned, which looks wrong when the content is a face and the seam jumps halfway down. Use match_size, or pad the shorter one to the same height before this node.

match_size compares area, not height or width. Two masks of 1024×1024 and 2048×512 have equal area, so neither gets resized - and the left-right join gives a canvas with a 1024-tall block and a 512-tall block. Read the result, not the intent.

It doesn't composite, it packs. There's no overlap or blend: the two regions sit side by side. If you need one mask covering overlapping regions, combine them with a mask-or / ImageCompositeMasked pairing instead. This node is for adjacency.

CategoryQG-tools/Mask

Inputs (4)

NameTypeDefaultDescription
mask1MASKThe first mask. Several frames are fine and stay several frames.
mask2MASKThe second mask, of any size.
match_sizeBOOLEANfalseOn: stretch the smaller mask to the bigger one's size, which also changes its aspect ratio. Off: both keep their own size and the leftover area stays black.
directionCOMBOleft-rightLeft-right joins them side by side; top-bottom stacks them vertically. Both lay the first mask at the top-left corner.

Outputs (1)

NameTypeDescription
MASKMASKThe joined mask as (B, H, W): one frame when both inputs had one, otherwise as many frames as the longer input.