ComfyUI Node

Mask Area Condition

Don't run FaceDetailer on every image — let the mask size decide

By a-und-b·Created about a year ago·Updated about a year ago· 5
Mask Area Condition
  • mask
  • is_below_threshold
  • mask_area_percent
  • mask_passthrough
threshold_percent10.0

Here's the workflow problem this node exists for: your FaceDetailer (or ADetailer-style) pass runs on every single image, whether the face needs it or not. A close-up portrait with a face filling half the frame gets the full detect-crop-resample-stitch treatment anyway - several seconds of compute for nothing. Impact Pack's detailer loop is great at what it does, but it's greedy when you let it run unconditionally. MaskAreaCondition is a tiny gate in front of that: it measures how much of the image a mask actually covers and hands you a boolean so your graph can decide before spending the time.

The mechanism is about as simple as a node gets. Feed it a MASK, and it counts the non-zero pixels and divides by the total pixel count, then multiplies by 100. That's your mask as a percentage of the whole frame. It compares that number against your threshold_percent and the comparison is strict: mask_area_percent < threshold_percent. So the output reads as "is the masked thing small?" - set the threshold to 10 and a face covering 6% of the frame is "below threshold" and True.

Just two inputs matter:

  • mask (MASK) - any mask tensor, which is convenient because the same math works on float masks (like blurred ones) and hard binary masks. Common sources: a SAM or bbox detector, or a Mask primitive.
  • threshold_percent (FLOAT, default 10, 0–100) - the cutoff. This is the knob you actually tune. Lower it if you only want to act on genuinely tiny detections; raise it and you'll trigger more often.

It gives you three outputs, and you mostly care about the first: is_below_threshold (BOOLEAN), the decision; mask_area_percent (FLOAT), the raw measurement if you want it for logging or math; and mask_passthrough (MASK), the original mask passed through so you don't need a parallel wire when chaining.

There's one design decision worth knowing before it bites you: an empty mask returns False, not True. The reasoning is sound - an empty mask means nothing was detected, so you do not want to fire the expensive inpaint pass. That's the safe default. The "gotcha" side of it is that you can't use an empty mask to mean "small object, do the thing." It means "skip."

This comes from the same pack as Select Data based on Condition, and they're designed as a pair: wire is_below_threshold into the selector and pick between two downstream paths. One honest caveat though - this node decides, it doesn't skip. ComfyUI evaluates the whole graph, so if you route both branches into a SelectData, the unselected branch still executes. Real compute savings need a downstream node that actually honors the boolean as a bypass. Think of MaskAreaCondition as the clean way to build the decision, not a magic compute-saver.

Installation is genuinely painless, because the pack has no dependencies beyond what ComfyUI already ships (plain torch, no models to download):

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/a-und-b/ComfyUI_MaskAreaCondition

Then restart ComfyUI. Or use ComfyUI Manager - search for "Mask Area Condition", click install, restart, reload the tab. Either way it lands under mask → conditional in the node menu. Since v1.1.1 it also logs the threshold, computed area, and decision to the console, which makes tuning the threshold a lot less guesswork. It's a small, no-commitment node - worth grabbing if you run detailers on batch or portrait-heavy work.

Categorymask/conditional

Inputs (2)

NameTypeDefaultDescription
maskMASK
threshold_percentFLOAT10.00–100

Outputs (3)

NameTypeDescription
is_below_thresholdBOOLEAN
mask_area_percentFLOAT
mask_passthroughMASK