Nodes/ComfyUI-projectorz-helper/Control Net Model Selector
ComfyUI Node

Control Net Model Selector

Automatic model selection for depth, normal, and pose maps

By GuillaumeBonvin·Created 6 months ago·Updated 5 months ago· 0
Control Net Model Selector
  • fallback_model
  • image
  • depth_model
  • normal_model
  • openpose_model
  • model
  • image_type
image_type

One input wire instead of three

Every ControlNet workflow starts with the same dumb decision: which model do I plug in? Depth map in, grab the depth model. Normal map in, grab the normal model. It's a two-second choice you make dozens of times a day, and it's exactly the kind of thing that shouldn't need a human in the loop.

This node makes the image answer the question. Feed it an image, tell it which three ControlNet models you keep around, and it figures out what kind of map it's looking at - depth, normal, or OpenPose - then hands you the matching model, no manual rewiring when you swap the source image. It's a small utility, but in a batch job or an animation workflow where the condition type changes frame to frame, it saves you from babysitting the graph.

It comes from ComfyUI-projectorz-helper, a "work in progress" pack by Guillaume Bonvin that bridges StableProjectorz (Igor Aherne's SD-based 3D texturing tool) with ComfyUI. The idea: Projectorz gives you a pile of depth, normal, and pose maps, and you want to feed them straight back into ComfyUI for refinement without inspecting each one by hand. This is the node that does the inspection.

How it works: lazy loading with a side of image forensics

The clever part isn't the selection - it's that the three model inputs are marked lazy. ComfyUI asks the node which inputs it actually needs before loading them, and this node answers based on the detected image type. Depth map detected and depth_model is connected? Only that model gets loaded into VRAM. Your other ControlNets stay on disk. On a 8 GB card, that's the difference between "sure, let me swap" and "CUDA out of memory, again."

The type detection itself (shared with the pack's ImageTypeCheck node) is a pixel heuristic: count unique colors, check if they're all grey (depth), check blue dominance plus unit-vector length (normal), check the OpenPose color palette (pose). It samples at most 512×512 pixels, so it's fast and good enough for a selector.

The inputs that actually matter:

  • fallback_model (required) - the ControlNet used when nothing matches, and honestly the one you'll rely on most.
  • image - the map to classify. Feed it a depth_model-compatible depth map and it routes accordingly.
  • image_type - a STRING override so you can skip image analysis entirely and just say "DepthMap". Handy when you know the type from upstream.
  • depth_model / normal_model / openpose_model - the per-type candidates, lazy-loaded.

Outputs: model (the chosen CONTROL_NET, ready to plug into a ControlNetApply) and image_type (the detected type as a STRING - handy if you want to log or branch on it).

Installing it

ComfyUI Manager is the easy route: search for "ComfyUI-projectorz-helper" and hit install. Or go manual:

cd ComfyUI/custom_nodes
git clone https://github.com/GuillaumeBonvin/ComfyUI-projectorz-helper

Then restart ComfyUI. There's no requirements.txt, no model downloads, no torch extra - this pack only needs the torch you already have. It'll appear under the "ProjectorzHelp" category in the node menu.

Where you'll get burned

Honest warning, straight from the source code: the OpenPose branch has a bug. When the detected type is OpenPose, the selection logic assigns normal_model instead of openpose_model. So if you wire openpose_model and leave normal_model empty, the node can return an empty model and your ControlNetApply will choke. Until it's fixed, treat openpose_model as decorative: for pose maps, either connect normal_model or lean on fallback_model. It's a "work in progress" pack - this is the kind of wart you're signing up for.

Also remember the detection is heuristic, not magic. A normal map with mostly flat neutral surfaces (low blue dominance) can slip through as a regular image and fall back to fallback_model. If your maps are oddly colored, pass image_type explicitly - that's what the override is for. And since _cached_type is reset after each run, the node re-analyzes every execution; feed it cheap inputs, not 4K renders, if you're batch-running.

CategoryProjectorzHelp

Inputs (6)

NameTypeDefaultDescription
fallback_modelCONTROL_NET
imageoptIMAGE
image_typeoptSTRING
depth_modeloptCONTROL_NET
normal_modeloptCONTROL_NET
openpose_modeloptCONTROL_NET

Outputs (2)

NameTypeDescription
modelCONTROL_NET
image_typeSTRING