ComfyUI Node

Mask Draw

See the mask sitting on top of the picture instead of guessing

By tom-m-2020·Created about a month ago·Updated 7 days ago· 1
Mask Draw
  • image
  • mask
  • image
◄line_width1►
◄color▾►
◄shape▾►
◄fillfalse►
◄opacity1.00►

Masks are the one thing in ComfyUI you cannot look at. You preview an image, you preview a latent, you even preview a conditioning, but a mask shows up as a grey rectangle in the node's thumbnail and nothing else. So you wire up a detailer or an inpaint, hit queue, and find out two minutes later that the mask was half a face off. Mask Draw exists to kill that round trip: it paints the mask's shapes directly onto your image so you can see whether the thing you masked is the thing you meant.

How it works

It is OpenCV with a colour mixer on top. For every plane in the MASK, it runs cv2.findContours in RETR_TREE mode, then skips any contour whose hierarchy parent is not -1 - in plain terms, it ignores holes and only draws outer boundaries. Each surviving contour gets either its bounding rectangle, an ellipse inscribed in that rectangle, or the contour path itself drawn as a polygon. Then that drawing is alpha-blended onto a clone of the image, so only the first three channels move. An alpha channel, if the image has one, is left alone.

Two consequences worth knowing before you wire it in:

  • It works on the whole image batch at once. Every mask plane is drawn into one shared canvas, and that single drawing is overlaid on every image in the batch. Feed it 8 frames and 8 masks and you get the union of all eight masks stamped on all eight frames. This is a diagnostic, not a per-frame annotator.
  • The threshold is "anything above zero." Contours come from a float-to-8-bit conversion, so a feathered mask draws at its outermost wispy edge, not at its visually solid part.

The inputs that matter

Wire an image and a mask in, get an image out - that output goes straight to Preview Image or Save Image, which is the point.

Of the knobs, shape is the one you'll actually think about. contour traces the mask honestly and is the right choice for checking a segmentation or a SAM mask. rectangle draws the bbox instead, which is what a YOLO/bbox detector pipeline actually feeds the sampler - those two shapes look very different, and the gap between them is exactly the seam problem people hit when a rectangular patch lands over a jawline. oval is there for the odd case where you want to eyeball a centred ellipse.

color gives you red, green, blue, yellow, black, white - nothing subtle. line_width goes 1–10 and only applies when fill is off; fill flips the whole shape solid, which swallows the image underneath. opacity (0–1) is your escape hatch for that: leave fill on and drop opacity to 0.25 and you get a tinted region you can still read through.

Install

ComfyUI Manager is the quick way - search ComfyUI Utility Suite (publisher tom-m), install, restart. By hand:

cd ComfyUI/custom_nodes
git clone https://github.com/tom-m-2020/ComfyUI-Utility-Suite

That's it for models: this pack needs none. It does need opencv-python-headless, which is the single line in the pack's requirements.txt and which Manager should install for you. If the node throws on import cv2, that pip step got skipped - run it yourself in ComfyUI's Python environment.

One thing to set expectations: the repo ships with an empty README. The pack is written against ComfyUI's newer V3 node API (from comfy_api.latest import io), which means it needs a reasonably current ComfyUI; on an old install the folder imports cleanly and shows nothing in the menu. And there is essentially no community writing about this pack yet - no tutorials, no threads - so the hover tooltips and the source are your documentation.

Where people get burned

ValueError: Mask Draw requires matching image/mask dimensions. The mask and the image have to be the same height and width. That's a real error, not a formatting complaint - a mask that came off a resized latent, or off a crop from earlier in the graph, will trip it. Resize the mask upstream.

Nothing appears on the image. Either the mask is empty, or it is inverted, or you swapped the wires. Easy to check: a mask of all zeros means findContours returns nothing and you get your input image back untouched, silently. Framing it honestly - an all-zero mask and a genuinely broken graph look identical at the output.

You can't see the mask through the highlight. Turn off fill, or drop opacity.

The one time this node is genuinely load-bearing rather than nice-to-have is in the detection path: when a detailer produces disappointing results, the argument is almost always about where the mask landed. Drawing it over the picture turns that argument into a five-second look.

CategoryUtility Suite/Mask

Inputs (7)

NameTypeDefaultDescription
imageIMAGE—
maskMASK—
line_widthINT11–10—
colorCOMBO6 options: red, green, blue, yellow, black, white
shapeCOMBO3 options: rectangle, oval, contour
fillBOOLEANfalse—
opacityFLOAT1.000–1—

Outputs (1)

NameTypeDescription
imageIMAGE—