VS Plate Drift Check
The sanity check that saves you from a matte full of ghosts
- white_plate
- black_plate
- bottle_mask
- glass_mask
- report
- difference_heatmap
Every difference matte is a subtraction, and every subtraction is only as good as the assumption that the two inputs are the same picture wearing different backgrounds. Break that assumption anywhere - a one-pixel shift, a crop stitched back slightly wrong, a model that nudged the label - and you don't get an error. You get an image that looks fine on white and has a ghost of the label embossed into the alpha channel. VS Plate Drift Check is the node that catches it before you ship, with a PASS / FLAG and a heatmap.
What it measures
Two things, both aimed at the "plates must agree" assumption:
Opaque-region agreement. It builds a region that should be bit-identical between the plates - pixels where the bottle mask is above 0.98, minus a dilation of the glass mask by 8 pixels so the regenerated neck can't contaminate the sample - and computes the mean and max absolute difference there. Anything above a mean of 0.002 is a fail. That's an extremely tight tolerance on purpose: on a correctly-built black plate (the ones VS Black Plate From White copies through unchanged) the true figure should be somewhere around zero, because the pixels are literally the same values.
Neck silhouette shift. It isolates the neck region, thresholds each plate's silhouette, and runs a phase correlation - an FFT-based translation estimate - to ask "how far did the silhouette move between plates". max_shift_px (default 1.0, up to 16) is your tolerance. One pixel is a sensible default: a whole-pixel shift is already enough to put a rim around the glass.
The report is JSON:
{
"status": "PASS",
"opaque_region_mean_abs_diff": 0.0,
"opaque_region_max_abs_diff": 0.0,
"neck_silhouette_shift_px": [0, 0]
}
The README's healthy reading is status: PASS. The difference_heatmap output is the useful part when it isn't: red marks the opaque-region difference (scaled ×4 and clipped, so a tiny disagreement is visible) and green marks the glass-region difference, so a faint displacement lights up visibly rather than as a near-black image you can't read.
Reading a FLAG
Two different failures, two different fixes:
- Non-zero opaque diff with a shift of zero means the plates weren't built from the same base - usually because the neck regeneration went through a crop-and-stitch with a stale
VS_CROPreceipt, or because something downstream of the black plate touched the body. The heatmap will show you exactly which region. - A shift of 1–2 pixels usually means the model's output for the crop was resized back through a slightly different box than it was cut from. Small, but at 0.002 tolerance it's fatal to the matte; re-stitch and check again.
What it can't tell you is whether the glass looks right. It's a consistency check, not a quality check. A perfectly aligned, perfectly consistent black plate can still contain implausible glass, because that region is invented.
Inputs and install
Inputs are white_plate, black_plate, bottle_mask, glass_mask and max_shift_px. Both masks are needed - the check needs to know what's supposed to be identical and what's supposed to be new. Outputs are report and difference_heatmap.
cd ComfyUI/custom_nodes
git clone https://github.com/andrewclass1/comfyui-vs-glassmatte
# restart ComfyUI
Or ComfyUI Manager → VS Glass Matte. Torch and numpy only; the FFT comes from torch.fft, so there's no SciPy or OpenCV requirement hidden in here.
Where it will annoy you
The opaque region excludes only 8 pixels of dilation around the glass mask. If your glass band is slightly too small - say you picked conservative top_frac / bottom_frac values in manual mode - real regenerated glass sits inside the "must be identical" sample and the check FLAGs on a plate that's actually fine. Widen the band, or accept the FLAG and read the heatmap instead of the status.
Conversely, a bottle mask that's slightly generous will pull backdrop into the opaque region, where white and black legitimately differ by the full range. You'll get a mean diff near 1.0 and a heatmap ring around the entire silhouette. That's a mask problem, not a plate problem - and honestly, that ring is the fastest way to see that your segmentation is off.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| white_plate | IMAGE | — | |
| black_plate | IMAGE | — | |
| bottle_mask | MASK | — | |
| glass_mask | MASK | — | |
| max_shift_px | FLOAT | 1.00–16 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| report | STRING | — |
| difference_heatmap | IMAGE | — |