Bart's Anatomy Defect Filter (Ollama) π
A local vision model as bouncer for your batch
- images
- passed
- failed
- report
- report_json
- passed_indices
- failed_indices
You queued 64 images. Somewhere in there are fifty you'd keep, ten mediocre ones, and four where somebody's arm grows out of a ribcage. Bart's Anatomy Defect Filter (AnatomyDefectFilter) sorts that for you: image batch in, passed and failed batches out, decided by asking a local vision model whether each picture has the defects you ticked.
Two things first. It doesn't fix anything - repairing the six-fingered hand is the detailing family's job (hand_yolov8 feeding an inpaint pass, not this). And "(Ollama)" is the honest part of the name: no cloud API, no key, but you do need an Ollama server reachable over HTTP.
How it works
Per image, the node slices one frame, downscales the longest side to max_side (768 default), encodes a quality-92 JPEG and makes exactly one POST to /api/chat on your ollama_url. The prompt is a checklist where each line describes a problem; the model answers with JSON giving, per check, found (is this problem present?), a 0β1 confidence and a short note. The request pins temperature: 0, a seed, format: json and a 1024-token cap.
The decision rule is one line: any check marked found at or above confidence_threshold fails the image. Parsing is forgiving (code fences, checks nested or top-level, 85 read as 0.85), and unparsable output gets one retry with a different seed before a hard error - so it never quietly files an image as passed when the model said nothing usable. The trap: lower confidence_threshold is stricter. At 0.25 you fail anything the model is a quarter sure about.
Inputs and outputs
Feed images. Point ollama_url at the server as the ComfyUI machine sees it, and set model to the name Ollama knows (ollama list) - a plain text field on purpose, because a browser-populated dropdown would turn your ComfyUI into an open proxy. It must be a chat-capable vision model: qwen3-vl:8b is the default, and llama3.2-vision, gemma3 and minicpm-v qualify too. An embedding model can't answer "does this hand have six fingers" - it only returns a vector.
Then the checkboxes: extra_limbs, missing_limbs, bad_fingers, smeared_limbs, impossible_pose, face_deformation, merged_bodies - four on by default, with the face and merged-body ones off, presumably because they fire on crowds. custom_criterion is free text evaluated like the built-ins; phrase it as a problem, one line, like a hand holding the cup has no thumb. Phrase it as an expectation and the verdict comes out inverted.
The rest is plumbing: max_side (hands need pixels, but bigger is slower), timeout, seed, append_no_think, num_ctx. Leave num_ctx at 4096 - Ollama otherwise sizes context from free memory, and the author measured 22GB of it for one image on a 32GB box, which dragged qwen3-vl:8b under 1 token/s.
Outputs: passed / failed as IMAGE batches, report (lines like #3 FAIL bad_fingers (0.85): six fingers on left hand), report_json, and passed_indices / failed_indices as comma-separated positions so you can reorder a filtered set. Usual wiring: failed into a Save Image under an output/rejected/ prefix, passed into a Preview. The text outputs always fire.
empty_branch covers a side ending up with no images: blocker (default) feeds it an ExecutionBlocker, so a Save on failed doesn't run - but every downstream node of that output is skipped, not just the Save - while placeholder emits one black image, so downstream always runs.
Install
Nothing to pip install - the Ollama client is stdlib urllib, and torch, Pillow and numpy already ship with ComfyUI. Find comfyui-bart-nodes in ComfyUI Manager, or clone it:
cd ComfyUI/custom_nodes
git clone https://github.com/bartenevve/comfyui-random-imageload-node comfyui-bart-nodes
Restart ComfyUI, then give it a server and a model (ollama pull qwen3-vl:8b, ollama list to check the name). There's a ready-made graph in the pack, example_workflows/05_anatomy_filter.json, listed in ComfyUI under Templates.
What actually goes wrong
cannot reach ollama at ... is the classic. The URL resolves from the ComfyUI process, not your browser, so a ComfyUI in Docker can't see your host's Ollama on localhost - use the host IP or a container name.
Empty answers. Thinking-capable models burn their whole budget and return nothing in content; keep append_no_think on for anything qwen3-family, and the error says when that's what happened. A mistyped model name surfaces as an Ollama error, not a dropdown warning - the cost of the plain text field.
It's slow, and it scales badly. One serial HTTP request per image, each a full vision forward pass, so check timeout (120s) before assuming it hung.
Judgement quality is the real limit, in both directions. A 7β8B VLM will pass a mangled hand and fail a perfectly good one; finger counting is close to its worst case. The community's version of that complaint: a vision judge "could easily misdetect the image as looking bad when you would think it looks good." Run it over ~20 images you've judged by hand, tune model and threshold there, then point it at hundreds - and treat report as a triage list to skim. Re-queuing an unchanged graph is cached, so you won't re-ask the model until something changes.
Finally: your images go to whatever ollama_url the workflow names, with no allowlist and no HTTP routes of this node's own, so a graph someone else wrote can aim it at any host reachable from yours. That's the same caution the whole "a VLM inside your graph" category earns - and it's exactly the category people install without reading. This one is MIT, readable, and tests its verdict parsing and Ollama client, which is more than most manage.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | β | |
| ollama_url | STRING | http://localhost:11434 | β |
| model | STRING | qwen3-vl:8b | β |
| extra_limbs | BOOLEAN | true | β |
| missing_limbs | BOOLEAN | false | β |
| bad_fingers | BOOLEAN | true | β |
| smeared_limbs | BOOLEAN | true | β |
| impossible_pose | BOOLEAN | true | β |
| face_deformation | BOOLEAN | false | β |
| merged_bodies | BOOLEAN | false | β |
| custom_criterion | STRING | β | |
| confidence_threshold | FLOAT | 0.600β1 | β |
| max_side | INT | 768128β4096 | β |
| timeout | INT | 1205β3600 | β |
| num_ctx | INT | 40962048β32768 | β |
| append_no_think | BOOLEAN | true | β |
| seed | INT | 00β2147483647 | β |
| empty_branch | COMBO | blocker | 2 options: blocker, placeholder |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| passed | IMAGE | β |
| failed | IMAGE | β |
| report | STRING | β |
| report_json | STRING | β |
| passed_indices | STRING | β |
| failed_indices | STRING | β |