2. Sharp Frame Selector
Keep only the sharp frames — either the top N, or one per scene
- images
- scores
- selected_images
- count
SharpFrameSelector is the other half of the SharpFrames duo in ethanfel/ComfyUI-Sharp-Selector. SharpnessAnalyzer scores your batch; this node does something about it. Feed it the images and their scores and it returns only the sharp ones - in the order you can actually use.
There are two ways to pick, and they solve different problems. That choice is the whole point of the node.
The two selection methods
best_n- rank every frame by score, keep the topnum_framesglobally. This is the "keep the 10 sharpest frames from this whole clip" option. Output is sorted back into timeline order, not score order, so the clip's structure survives.batched- walk the batch in windows ofbatch_size, and inside each window keep the single sharpest frame (if it clearsmin_sharpness). You get even temporal coverage: one representative frame per scene chunk instead of ten frames from the same stretch. This is the one you want when your goal is a varied dataset, because a global top-10 can all come from the same two seconds.
batch_buffer only matters for batched: it's how many frames the window skips between chunks, so windows don't overlap when your input is heavily oversampled. The stepping math is batch_size + batch_buffer, and the buffer is the fix this pack shipped to stop consecutive windows from double-counting the same sharp region.
min_sharpness is the floor filter. Any frame scoring below it is dropped in both modes. Default is 0, which means "keep everything," so it only does something if you've looked at real scores and picked a threshold.
Inputs and outputs that matter
- Inputs:
images,scores(from SharpnessAnalyzer),selection_method,batch_size,batch_buffer,num_frames,min_sharpness. - Outputs:
selected_images(the reducedIMAGEbatch) andcount(anINT- how many frames survived, handy for logging or routing).
Gotchas worth knowing
- If nothing clears the threshold, you get a black frame. The code returns a single 1×H×W tensor of zeros with
count = 0rather than an empty batch. It won't crash your workflow - which is the problem. A silent black frame can end up in a training set or get cheerfully upscaled. Watch thatcount. - Length mismatch is handled by truncation. If
imagesandscoresdisagree on length, the selector silently cuts both to the shorter. The analyzer always produces one score per frame, so this only bites if you wire in a different batch than the one you scored. - The
SHARPNESS_SCOREStype is pack-private. The selector only accepts the analyzer's output. Don't try to hand it a scores list from another pack - the wire won't connect.
Install and dependencies
ComfyUI Manager (search "ComfyUI-Sharp-Selector") or:
cd ComfyUI/custom_nodes
git clone https://github.com/ethanfel/ComfyUI-Sharp-Selector
Dependencies are just opencv-python and numpy (in requirements.txt), then restart. No model downloads anywhere in this pack. The typical spot for this node: after AnimateDiff or an img2img pass, before your FaceDetailer or upscaler, so you never waste a second pass on frames that were never going to survive it anyway.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| scores | SHARPNESS_SCORES | — | |
| selection_method | COMBO | 2 options: batched, best_n | |
| batch_size | INT | 241–10000 | — |
| batch_buffer | INT | 00–10000 | — |
| num_frames | INT | 101–10000 | — |
| min_sharpness | FLOAT | 0.00–10000 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| selected_images | IMAGE | — |
| count | INT | — |