OpenCV grabCut_1
Cutting a subject out of a photo, 1990s-style, with OpenCV grabCut
- img
- mask
- bgdModel
- fgdModel
- nparray_0
- nparray_1
- nparray_2
grabCut_1 is the OpenCV classic for pulling a foreground object out of a photo, wrapped as a node. It's the deterministic, no-model download - no BiRefNet, no SAM - graph-cut segmentation that's been in OpenCV for a decade and a half. If your subject sits inside a known rectangle and you want a mask without loading any weights, this is what you reach for.
Worth saying up front where it sits relative to the modern stack. The ML background-removal nodes the community actually recommends - BiRefNet, InSPyReNet - will beat grabCut on hair, fur, and semi-transparency every single time. grabCut is the different trade: zero VRAM, zero downloads, fully deterministic, and perfectly fine for a subject with clean edges inside a box you can define. It's also one of the rare segmentation options that runs happily on a single CPU core. Different tool, different job.
How it works
GrabCut takes your image plus a rough rectangle around the foreground and iteratively models "definitely background", "probably background", "probably foreground", and "definitely foreground" using color statistics plus a graph cut. Run it a few iterations and you get a labeled mask back. The mask input is where you're told the answer lives - with mode = 0 (GC_INIT_WITH_RECT) the rectangle drives everything and the mask is ignored.
The inputs that matter
img- your nparray (convert withImage2Nparrayfirst; Comfy'sIMAGEtensor won't feed it directly).rect- a STRING literal for the rectangle, e.g.[100, 100, 300, 300]asx, y, width, height. This is one of thoseast.parse()composite params, so type it as a Python literal. Wrong syntax gets youinvalid syntax (<unknown>, line 0).mask- an all-zero uint8 array of the same size as the image when using rect mode.bgdModel,fgdModel- the two internal 1×65 float64 buffers grabCut keeps between iterations. Here's the dragon: this auto-generated node lists them as required, so you have to wire something in. In raw OpenCV you'd passnp.zeros((1,65), np.float64).iterCount- iterations; 5 is a fine starting point.mode-0for init-with-rect,1for init-with-mask.
Three outputs: nparray_0 is the resulting mask (0/2 = background, 1/3 = foreground), and nparray_1/nparray_2 are the updated bgdModel and fgdModel. If you run grabCut iteratively, feed those back in on the next pass.
Installing it
Same as every node in this pack - install the whole pack:
cd ComfyUI/custom_nodes
git clone https://github.com/geroldmeisinger/opencv-comfyui
or search "OpenCV" in ComfyUI Manager. Then make sure OpenCV is present:
pip install opencv-contrib-python
No model files to fetch. That's the whole install.
Gotchas
Where people get burned: the required model buffers are the awkward part - most Comfy users don't have a node handy that emits a zeroed float64 array, so this node is genuinely fiddly compared to one-click ML cutouts. And remember the pack is auto-generated, so it's "ugly and complex" by the author's own admission. It works - but it's a scalpel, not a button.
You also can't feed a grayscale 8UC1 image to grabCut and expect a color segmentation - it wants the 3-channel image. If OpenCV complains about image type, check your cvtColor step.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| img | NPARRAY | — | |
| mask | NPARRAY | — | |
| rect | STRING | — | |
| bgdModel | NPARRAY | — | |
| fgdModel | NPARRAY | — | |
| iterCount | INT | — | |
| mode | INT | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| nparray_0 | NPARRAY | — |
| nparray_1 | NPARRAY | — |
| nparray_2 | NPARRAY | — |