MatAnyone2
Cut a moving subject out of video with a real matte, not a hard mask
- src_video
- foreground_mask
- foreground_MASK
- solid_color
- matte
- green_screen
MatAnyone2 is the video matting model people were asking for a ComfyUI node for back in early 2025, and this is that wrapper. If your job is "green-screen this clip of a person walking," a per-frame background-removal model won't cut it - it'll flicker, and the edges will crawl as hair moves between frames. MatAnyone2 is a video matting model: it takes a first-frame mask and propagates a per-pixel alpha matte through the whole clip using temporal memory, so hair and semi-transparency survive frame to frame. This node (display name "MatAnyone2", class MatAnyone2Compatible) is the bridge between that research repo and your ComfyUI graph.
How it actually works
Here's the part worth knowing before you install: this is a subprocess wrapper, not an in-process model. When you run the node it:
- Unpacks your
src_videoIMAGE batch into numbered PNG frames in a temp folder. - Resolves a first-frame mask (details below) and saves it as
first_frame_mask.png. - Spawns a separate Python process that runs the official MatAnyone2
inference_matanyone2.pyscript on those frames. - Scrapes the alpha output out of the official repo's
results/folder, resizes it to match your video, and composites.
That means the official pq-yang/MatAnyone2 repo must actually exist on disk - the node does not bundle it. If you treat this as a drop-in node you'll get an immediate "Official repo missing" error.
The inputs that matter
- src_video (IMAGE) - your clip as a frame batch. Load it with a
LoadVideoorVHS_VideoLoadnode. - foreground_MASK (MASK) or foreground_mask (IMAGE) - the first-frame trimap that tells the model what to cut. You need at least one; the MASK version is preferred if you feed both.
- mask_frame (INT, default 0) - which frame of that mask batch becomes the trimap. Note: it indexes into the mask, not the video.
- max_internal_size (INT, default -1) - passed to the official script as
--max_size. Leave at -1 unless the video is huge and you want it downscaled internally.
The n_warmup, max_mem_frames, and use_long_term knobs are declared in the UI but not actually wired to the subprocess in this version - I checked the source. Don't burn time tuning them; they're placeholders until the author plumbs them through.
The outputs
- matte (IMAGE) - the alpha as grayscale-RGB frames. Wire it into any compositing node (or
ImageToMaskif a real MASK type is what you need). - green_screen (IMAGE) - your subject composited over pure green (or your chosen
solid_color, which can come from the pack'sSolidColorBatchedhelper). Handy for previewing or feeding a chroma-key pipeline.
Installing it
Manager has it, but you're doing more than one click either way:
cd ComfyUI/custom_nodes
git clone https://github.com/ijoy222333/ComfyUI-MatAnyone2
cd ComfyUI-MatAnyone2
mkdir third_party && cd third_party
git clone https://github.com/pq-yang/MatAnyone2.git
cd MatAnyone2
# use the SAME python as ComfyUI:
python -m pip install -e .
The README's first troubleshooting step: if pip install -e . fails, open third_party/MatAnyone2/pyproject.toml and delete the cchardet, PySide6, and pyqtdarktheme lines from the dependency list - those are the usual culprits. Then pip install -r requirements.txt in the pack dir (it needs imageio, imageio-ffmpeg, omegaconf), and drop the model here:
mkdir -p ComfyUI/models/MatAnyone2
# matanyone2.pth from:
# https://github.com/pq-yang/MatAnyone2/releases/download/v1.0.0/matanyone2.pth
The node symlinks or copies that model into the official repo's pretrained_models/ so the script finds it - you don't have to touch the official layout yourself.
Where people get burned
- The subprocess runs with
sys.executable- the same Python that launched ComfyUI. If you installed the official repo into a separate venv, the subprocess won't see it. Everything must share one environment. - Blank 64×64 output = silent failure. The node catches every exception and returns tiny black tensors instead of erroring the graph; the real message goes to the console. If you get a little black blob, read your terminal output - the node prints the full command, model paths, and stderr.
- Expect overhead. Every run writes frames to disk and launches a fresh Python process. It's slower and heavier than an in-process node, and it's the price you pay for wrapping a research repo. For still images there's no reason to use this - grab BiRefNet from core instead. For moving video with hair and transparency, this is the one you reach for.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| src_video | IMAGE | — | |
| mask_frame | INT | 00–999999 | — |
| n_warmup | INT | 100–256 | — |
| max_internal_size | INT | -1-1–8192 | — |
| max_mem_frames | INT | 51–1024 | — |
| use_long_term | BOOLEAN | false | — |
| foreground_maskopt | IMAGE | — | |
| foreground_MASKopt | MASK | — | |
| solid_coloropt | IMAGE | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| matte | IMAGE | — |
| green_screen | IMAGE | — |