😺NKD Klein Box Detections
Delete the dog without painting anything, if you're on Klein 3
- detections
- boxes
- boxes
FLUX.3 Klein accepts bounding boxes as part of the prompt. The friction is that somebody has to produce those boxes, and drawing them by hand is useless for a workflow you want to queue and walk away from. This node is the walk-away half: YOLO or SAM3 finds the thing, Box Detections says what should happen to it, Presampling hands the list to Klein 3. Nobody draws.
Where this sits in the bigger picture
Boxes as a native part of the caption is an idea borrowed from the closed side - Ideogram 4 ships them inside its trained caption schema, precisely so regional control stops being a workflow bolted on top. BFL documented an equivalent format for FLUX.3 and this pack writes it. Same pattern, less surgery.
One caveat before you invest: FLUX 3 is Early Access, and Klein 3 is not the model most people have sitting in their models folder. If you're on Klein 2, this node loads, runs, and does precisely nothing - Presampling logs "boxes only work with Klein 3 - ignored" and drops them.
How it works
It all comes down to one input, detections, which takes three types and normalises them into a pixel box per object.
A MASK. If it's a batch (SAM3's individual masks), each mask is one object, which is what you want. A single mask gets split by connected components - so one painted blob covering two touching objects becomes one box around both. The source also drops blobs under 0.1% of the image area, which will quietly eat an earring.
SEGS. The Impact Pack's container for detected segments, so any Ultralytics/YOLO detector that speaks SEGS works. Each segment's box and label come through.
BOUNDING_BOX. SAM3 or RT-DETR style {x, y, width, height}. These carry no idea how big the image was, so the node leaves them in pixels and Presampling later measures them against the reference they claim to come from. If you upscaled or resized on the way in, they're wrong - use the detector's mask instead.
From there the pixel boxes become [top, left, bottom, right] on Klein's 0–1000 grid, ids run left to right, and the elements join whatever Presampling already has from its box editor.
The four settings that matter
detections and action are required. action applies to everything the node found in one shot:
remove- erase it. The obvious one: a photobomber, a logo, a stray hand.keep- hold it in place while the rest of the frame changes, and the way to name something the prompt only talks about.new- no source, sodescbecomes an instruction for what goes at that spot, including changes to what's already there ("Change the jacket to blue").
tag is the name your prompt will use. Put dog in there and you get <dog_1>, <dog_2>, numbered left to right, and chained nodes keep counting. Empty gets you the detector's label, a short desc, or <obj_1>. desc says what the thing is; empty falls back to the label.
Optional: boxes, for chaining one node per detection class (one for person with keep, one for dog with remove), and reference (advanced, 0–7) when you detected on something other than ref_0.
Output is a single boxes of type NKD_KLEIN_BOXES, into Presampling's boxes input. The node is also marked as an output node, so you can queue it on its own and it prints the tags it made - do that first, it saves guessing.
Install
ComfyUI Manager, search NKD Klein Tools, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Nekodificador/ComfyUI-NKD-Klein-Tools
Then restart. Nothing to pip install - requirements.txt is one comment saying torch and comfy_api come from ComfyUI itself, and pyproject.toml lists no dependencies. You need PyTorch ≥ 2.0, ComfyUI with FLUX.3 Klein support (the author tested Klein 3 on 0.40.0), and a detector from elsewhere: Impact Pack for SEGS, a SAM3 pack for masks or boxes. One wrinkle: Ultralytics is AGPL-3.0 down to the weights and runtime and has been the vector for an actual supply-chain compromise before. If you're selling what you make, the SAM path is cleaner.
Where people get burned
The bounding-box-mismatch case is the big one, and the pack warns about it in the log for a reason: detect on the same image Presampling receives, or send a mask.
Two objects detected as one means one box, so Klein treats them as a unit - use a mask batch. Conversely, a busy mask loses its small detections.
For keep and remove the boxes live on the reference, so the canvas needs ref_0's shape (Aspect Ratio As Reference, or Resize off), or they land somewhere you didn't intend. With a mask plus Use Detailing, boxes are remapped into the zoomed crop and anything outside it is skipped with a log line.
Last thing: without the prompt upsampler, any element your caption doesn't mention gets a sentence bolted on. It works, but your own words work better - for removals especially, naming what fills the gap ("fill its place with empty sand") is the difference between it leaving and it staying.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| detections | MASK,BOUNDING_BOX,SEGS | What was found: a MASK (SAM3, a segmenter, or one you painted), BOUNDING_BOX from SAM3 / RT-DETR, or SEGS from an Impact Pack detector (Ultralytics / YOLO). Each object becomes one element. BOUNDING_BOX doesn't say how big the image was, so it must come from the same image Presampling gets; if that one is resized, use the detector's mask instead. | |
| action | COMBO | remove | remove: erase it. keep: hold it in place while the rest changes (also how you name something the prompt talks about). new: desc says what goes there or how to change it ("Change the jacket to blue"). |
| tag | STRING | The name to use in your prompt: dog gives <dog_1>, <dog_2>… numbered left to right, and carries on across chained nodes. Empty: the detector's label, or obj. | |
| desc | STRING | What it is, or for new what to do. Empty: the detector's label when it gives one. Run the node to see the tags it made. | |
| boxesopt | NKD_KLEIN_BOXES | Elements from a previous Box Detections node, to chain several. | |
| referenceopt | INT | 00–7 | Which reference the detections were made on (ref_0 = 0). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| boxes | NKD_KLEIN_BOXES | — |