Image Quality Gate
Stop Hand-Filtering Your LoRA Dataset
- image
- badge
- verdict
- report
- blur_score
- sharpness_score
- noise_score
- clipping_score
- entropy_score
If you've trained a LoRA, you know the slog isn't the training - it's the dataset. Every guide says "high-res, crisp sources," then leaves you to eyeball a thousand generations and delete the blurred ones by hand. The moment someone in r/StableDiffusion posts a dataset-curation app, it gets upvoted because everyone feels that pain. ImageQualityGate is the ComfyUI-native version: one node that scores an image on five quality metrics and hands you back a verdict you can route on.
The trick that makes it interesting is the three-tier result. Instead of a hard PASS/FAIL that kills borderline images, you get PASS (green) / SO-SO (yellow) / FAIL (red) - which is exactly the right granularity for training data. Auto-accept the greens, manually review the yellows, bin the reds.
How it works
The node runs five analyses on the grayscale image: blockwise Laplacian variance for blur, a hybrid Laplacian+Tenengrad score for sharpness, a Gaussian-difference estimate for noise, a highlight/shadow clipping ratio, and Shannon entropy in bits. Each metric is checked against its threshold with a 1.4× "margin zone": a score inside the margin makes the image SO-SO rather than FAIL. One hard failure and the whole image fails - no partial credit.
Two design choices matter in practice. First, shot-type presets (close-up, medium, wide / full-body) multiply your slider values so the same base thresholds adapt to framing - a wide shot gets a looser blur bar, a close-up a stricter one. Plain blur detection would flag every shallow-depth-of-field portrait as blurry, so this is the difference between a usable gate and a nuisance. Second, center-weighted blur mode weights the middle of the frame 3×, the outer edges 0.3×, so background bokeh stops inflating the score. Set blur_mode to center-weighted for portraits; full image is fine for wide uniform shots.
The inputs that matter
Only a few are worth touching on first run:
blur_var_threshold- the one the README is most opinionated about. AI-generated images (especially distilled models like Z-Image Turbo) have inherently lower per-block Laplacian variance than real photos, so use 20–50 for AI output versus 80–150 for photographs. Leave it at the 30 default to start.shot_type-customuses your sliders raw; the presets scale them.blur_mode- as above.
The rest (sharpness_threshold, noise_threshold, clipping_threshold, entropy_threshold) are defaults you'll tune only after you've seen the report. All tooltips match the README, and the sliders are range-checked in the node definition, so it's hard to feed it nonsense.
The outputs are the point: verdict (INT: 0=FAIL, 1=SO-SO, 2=PASS) feeds straight into a Switch node to route images into accept/review/reject buckets; badge (IMAGE) is a color-coded PNG you can preview or save as proof of what passed; report (STRING) gives the per-metric breakdown; and the five raw score floats let you log or threshold on anything yourself.
Installing it
Via ComfyUI Manager, search "Image Quality Gate" (the pack is registered with the Comfy ecosystem - it ships a pyproject.toml with a [tool.comfy] block). Or manually:
cd ComfyUI/custom_nodes/
git clone https://github.com/0xBeycan/ComfyUI-ImageQualityGate.git
pip install -r ComfyUI-ImageQualityGate/requirements.txt
Then restart ComfyUI - it lands under image/analysis → Image Quality Gate. The requirements are just numpy, opencv-python, Pillow, and torch, and you almost certainly already have three of those; opencv-python is the only real new dependency. No model downloads, no API keys, nothing to fetch on first run.
Gotchas worth knowing
- It only scores the first image in a batch. The code analyzes
image[0]and ignores the rest of the tensor. If you feed a batch, you'll get a verdict for one image and silence for the others - split your batch and run it per-image. - The badge font falls back on Windows. It looks for DejaVu fonts at a Linux path and drops to PIL's tiny default bitmap font when they're missing, so the badge renders but the text is small. Cosmetic, not fatal.
- It's CPU-only and not fast. The blur pass is a Python double-loop running
cv2.Laplacianper block; at 1024×1024 with a 24px block that's a lot of small calls. It's fine for a few hundred dataset images, not for live previews.
Calibrate like this: run 30–50 images through in custom mode, read the report scores, and set thresholds so roughly 70–80% of your known-good images pass. Then switch to a preset for production. It won't judge aesthetics - nothing here catches a mangled hand - but for mechanically removing soft, noisy, clipped, or near-blank frames before training, it beats staring at a thousand thumbnails.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| shot_type | COMBO | 4 options: custom, close-up, medium, wide / full-body | |
| blur_mode | COMBO | 2 options: full image, center-weighted | |
| blur_threshold | FLOAT | 0.400–1 | Max blur ratio. Presets scale this; 'custom' uses as-is. |
| blur_var_threshold | FLOAT | 305–500 | Laplacian variance per block. AI-generated: 20-50, photos: 80-150. |
| sharpness_threshold | FLOAT | 15.00–500 | Min sharpness. Presets scale this; 'custom' uses as-is. |
| noise_threshold | FLOAT | 25.00–100 | Max noise level. Presets scale this; 'custom' uses as-is. |
| clipping_threshold | FLOAT | 0.0200–1 | Max clipping ratio. Presets scale this; 'custom' uses as-is. |
| entropy_threshold | FLOAT | 5.00–8 | Min entropy in bits. Presets scale this; 'custom' uses as-is. |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| badge | IMAGE | — |
| verdict | INT | — |
| report | STRING | — |
| blur_score | FLOAT | — |
| sharpness_score | FLOAT | — |
| noise_score | FLOAT | — |
| clipping_score | FLOAT | — |
| entropy_score | FLOAT | — |