🎭 Mask Selection (OreX)
An automatic mask for face, hair, clothes and skin — no painting required
- images
- image
- mask
Masking is the boring half of inpainting, detailing and compositing, and the half that decides whether the result looks pasted on. Every detailer works the same way: something finds the region, you re-render it, you paste it back. Manual inpainting makes you draw the region yourself. This node hands that job to Google's MediaPipe selfie segmentation, and it's more useful than the average person-segmenter because it gives you parts - face, hair, body skin, clothes, accessories, background - as switches you can mix.
What you're actually getting
The model underneath is selfie_multiclass_256x256, MediaPipe's six-class segmenter. If you've used LayerMask's PersonMaskUltra V2 from ComfyUI_LayerStyle_Advance, you already know the output - the source file calls this an independent re-implementation of it, minus the LayerStyle dependency and with the matte backends wired in directly. It's also the licence-clean pick: person YOLO weights pull Ultralytics' AGPL into anything you sell, MediaPipe is Apache 2.0, and there's no detector checkpoint to source.
Reach for it to build a mask for a detailing pass, for selective exposure work (the classic case: two exposures of one shot, mask the person, composite), for background replacement, or just as a cheap mask source for SetLatentNoiseMask. For a specific object rather than a person part, you want SAM or Grounded SAM instead.
How it works
MediaPipe segments each image at 256×256 and returns one confidence map per class: 0 background, 1 hair, 2 body skin, 3 face skin, 4 clothes, 5 accessories. The node stacks the maps for the classes you enabled and keeps the per-pixel maximum, so face + hair gives you the union, not the intersection. That value is hard-thresholded at confidence - which is why a higher number gives you a tighter, smaller mask.
The 256×256 part is the honest catch: your 1024px image comes back with low-resolution boundaries. That's what the detail stage is for. With process_detail on, the node builds a trimap - detail_erode shrinks the mask to a solid-foreground core, detail_dilate grows an "unknown" band around it, everything outside is definite background - and hands it to a matting model (VITMatte) or alpha estimator (PyMatting). black_point and white_point remap the final alpha, so you can crush near-zero values to black or lift the top toward solid white.
GuidedFilter skips the trimap entirely and edge-aware-filters the mask against the image with a plain cv2.boxFilter implementation: no sub-model, no download, fast, and noticeably softer than VITMatte.
The inputs that matter
images- the batch, processed image-by-image in a Python loop, so a 20-image batch is 20 sequential segmenter calls. Batch it, but don't expect it to be free.face,hair,body,clothes,accessories,background- the six switches. Onlyfaceis on by default. All off returns an empty mask (the author's explicit behaviour, not an error).confidence(default 0.4, 0.05–0.95) - the threshold on the raw confidence maps. Raise it if stray background pixels cling to the hairline; lower it if thin strands drop out.detail_method-VITMatte/VITMatte(local)/PyMatting/GuidedFilter. VITMatte is the quality pick, GuidedFilter the fast one.max_megapixels(default 2) anddevice- VITMatte only. Above the megapixel budget, VITMatte runs on a downscaled copy and scales the mask back up, so on a 4K frame that default quietly throws away the edges you enabled the node for. Raise it if you have VRAM.
Two outputs. image is the source frame with the mask written into its alpha channel - four channels, fine for SaveImage, but switch to the mask output if a downstream node assumes RGB. mask is the plain MASK you wire into SetLatentNoiseMask, ImageCompositeMasked or an inpainting conditioning node. Want the background instead of the person? Select background alone.
Install
Via ComfyUI Manager, search for OreX (the registry name is "Orex Nodes") and install the pack, which pulls its dependencies for you. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/orex2121/comfyui-OreX
# then install the pack's requirements into the Python that runs ComfyUI
The pack ships requirements.txt with mediapipe, opencv-contrib-python, pymatting, transformers>=4.43.2 and Pillow, plus audio/video extras for its other nodes. torch is deliberately excluded, so letting Manager install requirements won't touch your CUDA build. Restart ComfyUI afterwards, not just "Refresh". Nothing else to fetch by hand: the first run pulls selfie_multiclass_256x256.tflite from Google's model storage into ComfyUI/models/mediapipe/, and the first VITMatte run pulls hustvl/vitmatte-small-composition-1k from Hugging Face.
Things that will bite you
"requires mediapipe" on the first run. The import is lazy - it happens inside the node, not at pack load - so a missing module gives you a clean error on Run and nothing else. Don't reinstall the pack; install it into ComfyUI's own interpreter:
python -m pip install mediapipe
# portable/Windows build:
python_embeded/python.exe -m pip install mediapipe
People still lose days to this with the LayerStyle ancestor of this node, usually because they pip-installed into a different Python than the one ComfyUI launches with.
VITMatte(local) can't find a model. Plain VITMatte downloads into the Hugging Face hub cache, while VITMatte(local) loads with local_files_only=True from ComfyUI/models/vitmatte and nothing else - so on a fresh install it errors. Fix: run VITMatte once, copy the snapshot's config.json + model.safetensors into ComfyUI/models/vitmatte, then switch.
PyMatting is slow, and it's the CPU one. It runs a closed-form alpha matting solve with maxiter=500 at full resolution, and device does nothing for it - on a 2MP frame, be ready to wait.
Hair is the hard case for everyone. Person segmentation is weakest at flyaway strands and semi-transparent material; that's why matting backends exist. If hair still looks chewed after VITMatte, loosen detail_dilate and lower black_point rather than turning the threshold down until the mask swallows the background.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| face | BOOLEAN | true | — |
| hair | BOOLEAN | false | — |
| body | BOOLEAN | false | — |
| clothes | BOOLEAN | false | — |
| accessories | BOOLEAN | false | — |
| background | BOOLEAN | false | — |
| confidence | FLOAT | 0.400.05–0.95 | — |
| detail_method | COMBO | 4 options: VITMatte, VITMatte(local), PyMatting, GuidedFilter | |
| detail_erode | INT | 61–255 | — |
| detail_dilate | INT | 61–255 | — |
| black_point | FLOAT | 0.010.01–0.98 | — |
| white_point | FLOAT | 0.990.02–0.99 | — |
| process_detail | BOOLEAN | true | — |
| device | COMBO | 2 options: cuda, cpu | |
| max_megapixels | FLOAT | 2.01–999 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |