Decode Blind Watermark (Advanced)
Recovering a Watermark After Someone Tried to Kill It
- image
- watermark
The basic Decode Blind Watermark node assumes the world was nice to your image: it reads all three YUV channels with default settings and hopes for the best. This node is for when the world wasn't nice. It's the same extraction routine, but you get to re-scale the image back to its original size, pick which color channels still carry the watermark, flip inverted channels, and match every parameter you used at encode time. It's the difference between "did you keep the receipt" and actual forensics.
Same pack, same story as the rest: ComfyUI-BlindWatermark by lihaoyun6, CPU-only wrapper around the fire-keeper/BlindWatermark library. No models, no GPU.
The inputs that do the work
- original_seed - still the load-bearing input. Must match the encode seed.
- watermark_size, strength, block_size, robustness - must match what you encoded with. This is the parameter "complete the sentence" requirement: encode with Advanced at non-defaults, decode here with the identical numbers. It's fiddly, but it's the only way the basic node's hardcoded defaults stop working.
- original_width / original_height (default −1) - the recovery trick. If someone resized your image before it came back to you, set these to the original dimensions and the node resizes the incoming image back before extracting. Resizing is one of the most common ways a watermark gets smeared; un-smearing it first is half the battle. Leave both at −1 to skip the resize.
- y_channel / u_channel / v_channel (each on/off/invert) - the watermark is embedded in all three YUV channels. If an edit destroyed one channel - heavy chroma subsampling wrecks U and V, for instance - turn the dead one off and extract from the survivors.
invertflips a channel's bits, for when a channel comes back as a photographic negative of the watermark. You need at least one channel on, or the node throws an error.
The output is a watermark image, blended from whichever channels you enabled - wire it to a Preview/Save node. One channel will be noisier than three; that's expected, it's a trade you make consciously.
How to actually use it
Think of this as a sequence, not a one-shot. First decode with all three channels on and defaults, and look at the result. If the watermark is there but dim, that's fine - it extracted. If it's a negative, flip one channel to invert at a time (a channel inverts independently of the others, so find the culprit). If it's static, set original_width/original_height if the image was resized, then try toggling channels off one by one to find what survived. There's no autodetect - you're the detector, and the node gives you the instruments.
Installing
ComfyUI Manager → "ComfyUI-BlindWatermark", or clone into custom_nodes/ and pip install -r requirements.txt, then restart:
git clone https://github.com/lihaoyun6/ComfyUI-BlindWatermark
Dependencies are pillow, opencv-python, numpy, pywavelets, numba - CPU-only, and the first run pays a few seconds of numba JIT compile. If you encoded at defaults with the basic node, you don't need this node at all; reach for it only when the basic decode comes back empty and the image went through some life before you got it.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| original_seed | INT | 00–1125899906842624 | — |
| original_width | INT | -1 | — |
| original_height | INT | -1 | — |
| watermark_size | INT | 64 | — |
| strength | INT | 3010–98 | — |
| block_size | COMBO | 6 | 4 options: 2, 4, 6, 8 |
| robustness | COMBO | 1 | 3 options: 1, 2, 3 |
| y_channel | COMBO | on | 3 options: on, off, invert |
| u_channel | COMBO | on | 3 options: on, off, invert |
| v_channel | COMBO | on | 3 options: on, off, invert |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| watermark | IMAGE | — |