A single-node image quality control system for ComfyUI. Designed for automated filtering of AI-generated images in LoRA training dataset pipelines.
Analyzes 5 quality metrics, applies shot-type-aware threshold scaling, and outputs a visual PASS / SO-SO / FAIL badge — all in one node.
- 5 Quality Metrics — Blur, Sharpness, Noise, Clipping, Entropy
- Three-Tier Verdict — PASS (green), SO-SO (yellow), FAIL (red). No more hard binary decisions on borderline images.
- Center-Weighted Blur Detection — Ignores background bokeh, focuses on subject sharpness
- Shot Type Presets + Custom Mode — Use built-in profiles or go fully manual with raw slider values
- Visual Badge Output — Color-coded badge with per-metric breakdown, directly previewable in ComfyUI
- Integer Verdict Output — 0=FAIL, 1=SO-SO, 2=PASS for routing through Switch nodes
Standard blur detection treats the entire image uniformly. Portrait shots with shallow depth of field get flagged as blurry even when the subject is perfectly sharp. The center-weighted blur mode weights the center of the image 3x heavier than the edges, so background bokeh doesn't inflate scores.
Additionally, AI-generated images (especially from distilled models like Z-Image Turbo) have inherently lower block-level Laplacian variance than real photographs. The blur_var_threshold parameter lets you calibrate for this — set it to 20-50 for AI content instead of the 80-150 range used for real photos.
cd ComfyUI/custom_nodes/
git clone https://github.com/0xBeycan/ComfyUI-ImageQualityGate.git
pip install -r ComfyUI-ImageQualityGate/requirements.txtRestart ComfyUI. The node appears under image/analysis → Image Quality Gate.
When a preset is selected, your slider values are multiplied by the profile's scaling factors. This means the same base thresholds automatically adapt to different shot types.
| Metric | Close-up | Medium | Wide / Full-body |
|---|---|---|---|
| Blur | ×0.6 (stricter) | ×1.0 | ×1.6 (looser) |
| Sharpness | ×1.5 (stricter) | ×1.0 | ×0.6 (looser) |
| Noise | ×0.8 | ×1.0 | ×1.3 |
| Clipping | ×0.8 | ×1.0 | ×1.2 |
| Entropy | ×1.1 | ×1.0 | ×0.85 |
| Block size | 16px | 24px | 32px |
When custom is selected, all multipliers are 1.0. Slider values are used exactly as-is. Block size defaults to 24px. Use this when you want full manual control or when calibrating thresholds for a new model.
Instead of a hard PASS/FAIL binary, the node evaluates each metric into three states:
| State | Badge Color | Meaning |
|---|---|---|
| PASS | Green | All metrics within threshold |
| SO-SO | Yellow | No hard failures, but some metrics in the margin zone (within 1.4× of threshold) |
| FAIL | Red | At least one metric exceeds the margin zone |
The verdict output is an integer: 0 = FAIL, 1 = SO-SO, 2 = PASS. Use this with a Switch node to route images into three buckets: auto-accept, manual review, and auto-reject.
For "lower is better" metrics (blur, noise, clipping):
score ≤ threshold→ PASSthreshold < score ≤ threshold × 1.4→ MARGINAL (contributes to SO-SO)score > threshold × 1.4→ FAIL
For "higher is better" metrics (sharpness, entropy):
score ≥ threshold→ PASSthreshold / 1.4 ≤ score < threshold→ MARGINALscore < threshold / 1.4→ FAIL
| Input | Type | Default | Description |
|---|---|---|---|
image |
IMAGE | — | Input image tensor |
shot_type |
Dropdown | custom | custom, close-up, medium, wide / full-body |
blur_mode |
Dropdown | full image | full image or center-weighted |
blur_threshold |
Float | 0.40 | Max blur ratio |
blur_var_threshold |
Float | 30.0 | Laplacian variance per block (AI: 20-50, photo: 80-150) |
sharpness_threshold |
Float | 15.0 | Min sharpness score |
noise_threshold |
Float | 25.0 | Max noise level |
clipping_threshold |
Float | 0.02 | Max clipping ratio |
entropy_threshold |
Float | 5.0 | Min entropy in bits |
| Output | Type | Description |
|---|---|---|
badge |
IMAGE | Visual PASS/SO-SO/FAIL badge |
verdict |
INT | 0=FAIL, 1=SO-SO, 2=PASS |
report |
STRING | Text report with per-metric breakdown |
blur_score |
FLOAT | Raw blur ratio |
sharpness_score |
FLOAT | Raw sharpness value |
noise_score |
FLOAT | Raw noise level |
clipping_score |
FLOAT | Raw clipping ratio |
entropy_score |
FLOAT | Shannon entropy in bits |
┌─ verdict=2 → [SaveImage] (dataset/)
[Generate] → [ImageQualityGate] → verdict → verdict=1 → [SaveImage] (review/)
└─ verdict=0 → (discard)
- Generate 30–50 images with your pipeline
- Run through the node in
custommode - Check the
reportoutput — look at score distributions - Adjust thresholds so ~70-80% of your "good" images pass
- Switch to a preset for production runs
MIT