ChameleonMask
Give it a clean reference and it finds what changed — a mask of the difference
- dst
- src
- optional_roi_mask
- IMAGE
- IMAGE
ChameleonMask is a change-detection node with a joke for a name (the author's own comment in the source is literally "wtf would I name this node as?"). You give it two images - a clean reference and the image with something added or changed - and it returns a mask of exactly where they differ. The classic use: you have a stable background (an empty room, a studio backdrop, a scene without the subject), someone or something appears in frame, and you want a cutout of the newcomer without any segmentation model.
The math is satisfyingly old-school. It computes the absolute difference between the two images (in whichever channel you choose), blurs it, Otsu-thresholds it into a hard mask, then runs it through a morphological pipeline - close, open, and a size pass - to fill holes and kill specks. A final blur and contrast boost soften the edges into something a composite can actually blend. That's a complete background-subtraction chain in one node, which is why it earns its place in a masking-focused pack.
Inputs that matter
dstandsrc- the two images to compare.dstis your reference ("before"),srcis the changed one ("after"); the mask highlights whatsrcgained.mode- which channel to compare: GRAY (luminance, the default and usually the right call), VALUE / LIGHTNESS, or HUE / SATURATION (HSV) / SATURATION (HSL). HUE mode is the trick when brightness didn't change but color did - it even handles hue's circular wrap so red-vs-magenta doesn't false-positive.thresh_blur(default 30) - smooths the difference before thresholding; raise it if your reference has noise.close_dist/open_dist(defaults 32) - morphological closing (fill holes) and opening (remove specks).size_dist(default 8) - grows the mask when positive, shrinks it when negative.mask_blur(default 64) andcontrast_adjust(default 2.4) - soften and sharpen the final edges.output_format- RGB or GRAY.optional_roi_mask- restrict the whole operation to a region of interest (the area where change is possible), which kills false positives outside it.
Outputs: the IMAGE mask, plus a second IMAGE - the raw difference image, which is there for debugging. Use the first, glance at the second.
Install
Part of bmad4ever/comfyui_bmad_nodes, under Bmad/CV/C.Photography:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_bmad_nodes
cd comfyui_bmad_nodes
pip install -r requirements.txt
Restart, or ComfyUI Manager → search comfyui_bmad_nodes. Heavily OpenCV (opencv-python~=4.8.1.78 in requirements.txt); no models.
Gotchas
The whole method assumes a good reference. If your "before" has camera noise, lighting drift, or the scene isn't static, the difference image will be full of ghosts and no amount of morphology fully saves you - that's what thresh_blur, the ROI mask, and mode: GRAY are for. Also, the two output sockets confuse people: only the first is the usable mask; the second is debug. And note size_dist's sign convention (positive dilates, negative erodes) - it's easy to flip and wonder why the mask shrank.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| dst | IMAGE | — | |
| src | IMAGE | — | |
| thresh_blur | INT | 30 | — |
| close_dist | INT | 32 | — |
| open_dist | INT | 32 | — |
| size_dist | INT | 8 | — |
| mask_blur | INT | 64 | — |
| contrast_adjust | FLOAT | 2.40–20 | — |
| mode | COMBO | GRAY | 6 options: GRAY, VALUE, LIGHTNESS, HUE, SATURATION (HSV), SATURATION (HSL) |
| output_format | COMBO | RGB | 2 options: RGB, GRAY |
| optional_roi_maskopt | IMAGE | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| IMAGE | IMAGE | — |