Nodes/ComfyUI_Swwan/Image Batch Filter (Swwan)
ComfyUI Node

Image Batch Filter (Swwan)

Throw out the black frames and get told which ones

By aining2022·Created 10 months ago·Updated about 18 hours ago· 33
Image Batch Filter (Swwan)
  • images
  • replacement_image
  • images
  • removed_indices
◄empty_color0, 0, 0►
◄empty_threshold0.01►

Empty frames happen more than they should

A batch in ComfyUI is a tensor, and a tensor can't have holes. So when something upstream "skips" a frame - a loop that didn't run, a detector that found nothing, a segment that failed and got padded - you don't get a gap. You get a black frame, or a frame of some placeholder colour, sitting in the middle of your video like a missing tooth.

Image Batch Filter finds those frames and either removes them or replaces them. It's KJNodes' ImageBatchFilter re-registered by the Swwan pack, and it's the kind of node you don't know you need until you're scrubbing through a 120-frame render looking for the two frames that came out black.

How "empty" is decided

Each frame is compared against empty_color - a mean of the absolute per-pixel difference across the whole frame - and if that mean is at or below empty_threshold, the frame counts as empty.

  • empty_color - a string, default 0, 0, 0. Integers only, on a 0–255 scale: each part is parsed and divided by 255. 128, 0, 0 is fine; 0.0, 0.0, 0.0 raises a conversion error, which surprises people who've just come from a node that wanted floats.
  • empty_threshold - 0 to 1, default 0.01. This is the tolerance, and it exists because a "black" frame that's been through a VAE encode/decode isn't really zero - it's a couple of levels off in every channel. 0.01 catches near-black without catching genuinely dark content. Lower it if you're dropping frames you wanted; raise it if a few are still sneaking through.

Two behaviours, one switch

Without replacement_image, empty frames are dropped and the batch comes back shorter. That's the mode you want when you're cleaning up a clip before encoding.

With replacement_image wired, empty frames are replaced in place with that image and the batch keeps its original length. The replacement is upscaled with Lanczos to match if the dimensions differ. One detail from the implementation: only the first frame of whatever you wire in is used, so a multi-frame replacement image gives you the same frame repeated.

Either way you get a second output, removed_indices - a STRING listing the indices that were caught, comma-separated. That's the good half of this node. It's trivially easy to log, easy to print, and easy to branch on: wire it into a text node and you can see which frames the filter considered empty, which is usually how you find the actual bug upstream.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/aining2022/ComfyUI_Swwan
cd ComfyUI_Swwan
python -m pip install -r requirements.txt

Manager → ComfyUI Swwan, restart, hard-refresh. No models, no optional dependencies; it's a mean-and-threshold over tensors.

Practical notes

It shortens the batch, and downstream nodes may not like it. Anything that assumed a fixed frame count - a model expecting 4n+1 frames, a conditioning tensor with a matching length - will now be mismatched. The replacement_image mode exists mostly for that: keep the count stable, swap the content.

Black isn't the only empty. If your failure mode is white frames, or a magenta placeholder, set empty_color to match. The node does no cleverness: it looks for the colour you tell it.

Frames that are legitimately dark will be caught. A fade-to-black in an otherwise good clip, or a night scene, can sit under the threshold. The removed_indices string is what saves you here - check the list before you trust a shortened output, because a filter that silently eats your opening fade looks exactly like a model that generated fewer frames than you asked for.

And note it only handles the colour test. Frames that are garbage but not empty - a smear, a duplicate - sail right through. For deduplication you want an index-node plus a comparison, not this.

CategorySwwan/Advanced/Batch

Inputs (4)

NameTypeDefaultDescription
imagesIMAGE—
empty_colorSTRING0, 0, 0—
empty_thresholdFLOAT0.010–1—
replacement_imageoptIMAGE—

Outputs (2)

NameTypeDescription
imagesIMAGE—
removed_indicesSTRING—