VS Black Plate From White
The deterministic half of the black plate, done in one subtraction
- white_plate
- bottle_mask
- IMAGE
Difference matting needs two plates of the same bottle: one shot on white, one on black. The naive way to get the black plate is to send the whole image back to a generative model on a black background, and then you've got two bottles that disagree about everything - different label, different reflections, different proportions - and the matte turns into noise. This node is the pack's answer to that: build the black plate out of the white plate using the silhouette, so the opaque parts are identical by construction. Only the glass gets regenerated later.
The arithmetic
For each pixel: normalise the bottle mask between clear_below and solid_above, then output white - (1 - m). Which means:
- Where the mask is fully solid (
m = 1), you getwhite - 0- the pixel is copied unchanged. The body of the bottle, the label, the cap: bit-identical between plates. - Where the mask is fully clear (
m = 0), you getwhite - 1, which is the white backdrop contribution removed.
The mask gets remapped first: (m - clear_below) / (solid_above - clear_below), clamped to 0–1. So clear_below (default 0.02) is the mask value under which a pixel counts as background, and solid_above (default 0.95) is the value above which it's treated as fully opaque. The author's tooltip for that second one is the useful sentence: "Mask values above this count as fully opaque, so the body never goes see-through." That's the guarantee - the node is biased so it can't accidentally punch holes in the bottle body because your segmentation was a little soft at the edge.
Output is a single unnamed IMAGE - the black-plate base. Everything in the glass band is now garbage-ish (it's an inverted remnant of the white plate), and the pipeline replaces that region with Flux Fill on black, cropped via VS Mask Crop and pasted with VS Mask Stitch.
Why this design is right
Two reasons, and both are worth internalising before you build your own version of this.
First, the matte is a subtraction. If the two plates differ anywhere outside the transparent region, the difference matte reports false alpha there. Deterministic construction makes that impossible rather than merely unlikely. That's the same instinct behind the crop-and-stitch pattern in inpainting, where not passing unmasked pixels through the VAE is a structural guarantee instead of a discipline.
Second, it localises the guess. A generative model is going to make something up for the glass, because no model can measure what's behind an object. Confining that fabrication to the neck band means the client can compare the label and the bottle body to the real product photo and find them identical, because they are identical.
Install
Manager → VS Glass Matte, or:
cd ComfyUI/custom_nodes
git clone https://github.com/andrewclass1/comfyui-vs-glassmatte
# restart ComfyUI
No pip installs at all - dependencies = [], torch and numpy only. Nothing to download.
Where people get burned
The whole node assumes the white plate is already normalised. Feed it a plate whose backdrop is 0.94 and white - (1 - m) leaves 0.06 of grey floating in the background; in the matte that turns into a uniform low-alpha haze you cannot get rid of without clipping, and clipping eats your real glass. Run VS Normalize White Plate first. That ordering isn't a suggestion in the README, it's the pipeline.
Second: clear_below above your mask's edge value will start treating the bottle's soft edge as background and shave it. If you use a matting model that produces gentle alpha ramps, lower clear_below rather than raising solid_above.
Third: the two plates must end up the same size before VS Difference Matte sees them, and that node raises a plain ValueError if they aren't. If you regenerate the neck through a crop, make sure the stitch put it back on the exact base you cropped from.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| white_plate | IMAGE | — | |
| bottle_mask | MASK | — | |
| solid_above | FLOAT | 0.9500.5–1 | Mask values above this count as fully opaque, so the body never goes see-through. |
| clear_below | FLOAT | 0.0200–0.5 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |