Nodes/ComfyUI illumorae/Controlnet Image Preprocess Cached (illumorae)
ComfyUI Node

Controlnet Image Preprocess Cached (illumorae)

Canny, LineArt and LeReS Depth With an On-Disk Cache

By CorvaeOboro·Created 8 months ago·Updated 2 days ago· 1
Controlnet Image Preprocess Cached (illumorae)
  • image
  • image
  • cache_hit
source_path
preprocessor
update_cache_if_newertrue
force_refreshfalse
source_name
source_date_modified0
debugfalse
low_threshold0.15
high_threshold0.30
coarse1.0
resolution512
rm_nearest0.0
rm_background0.0
boost

The slow part of every ControlNet workflow

ControlNet conditions on a structure map - edges, lineart, depth - and a preprocessor node upstream of the ControlNet Apply node has to make that map before the sampler runs. ComfyUI will skip that node while nothing upstream of it changes, but the map gets recomputed the moment the graph is rebuilt, the source varies per run, or you restart - and the depth pass is the slow part of the graph. LeReS in particular isn't cheap: it spins up a resnext101 depth net plus a pix2pix post-processor per compute. In a variation-exploration loop, which is this pack's whole reason for existing, that's a tax you pay over and over.

This node runs the preprocessor once, drops the result as a PNG beside your source image, and loads that instead on every run after. It also does not need comfyui_controlnet_aux: lineart and LeReS are reimplemented inside this node's own folder, and canny calls ComfyUI's core Canny node. The aux pack is the one with a years-long trail of ImportError threads attached - skipping it is a real selling point, not marketing.

How the caching works

The cache lives beside the source, not in a global folder:

<source_dir>/<source_stem>/controlnet/canny.png
<source_dir>/<source_stem>/controlnet/lineart.png
<source_dir>/<source_stem>/controlnet/depth_leres.png

The leres preprocessor writes itself as depth_leres.png to match the naming everyone's ControlNet folders already use. Give the node a folder plus a source_name instead of a full path and the same scheme applies under <source_path>/<source_name>/controlnet/.

Freshness is a timestamp comparison - source mtime versus cache mtime - and three switches steer it. update_cache_if_newer (default True) is the auto-refresh setting: edit the source, get a fresh map; don't touch it, get the cached one. Set it False and the cache wins as long as a PNG exists, timestamp be damned - a frozen condition map nothing is allowed to disturb. force_refresh ignores the cache and re-runs, overwriting the PNG.

Both timestamps feed the node's IS_CHANGED key, so ComfyUI re-queues it when either file changes and skips it entirely when neither has. That's the plumbing that makes "never recompute" stick across runs, not just within one.

Inputs and outputs that matter

The required input you'll fight with is source_path: the full path to the image file, or the folder containing it if you also fill source_name. source_name is the file's stem without extension - pass portrait, not portrait.png, or you get a folder literally named portrait.png holding your cache. Leave source_path empty and the node still runs (wiring image is enough), but it writes nothing, so you never get a hit.

preprocessor picks canny, leres or lineart, and only that choice's parameters do anything:

  • Canny: low_threshold / high_threshold, defaults 0.15 / 0.3, matching the core node.
  • LineArt: coarse and resolution. Watch coarse - anything above 0.5 selects the coarse model and the default is 1.0, so out of the box you get bold sketch strokes, not fine lines.
  • LeReS: resolution, rm_nearest, rm_background (0 means keep everything; the sliders run to 100), and boost (disable/enable). Set resolution near your source's long edge in steps of 64 - the 512 default is too soft for a 1536px input, and a soft depth map stays soft whatever ControlNet weight you throw at it.

Two outputs. image is the map - wire it into the ControlNet Apply node like any preprocessor's output. cache_hit is True when the PNG was loaded and the preprocessor never ran - handy to preview, or to gate a log line on real recomputes. Turn debug on for the first setup run; it prints the resolved paths, the hit/miss and whether the write succeeded.

Installing it

Manager first: search "illumorae" and install the pack. Manually, from your ComfyUI root:

cd ComfyUI/custom_nodes
git clone https://github.com/CorvaeOboro/ComfyUI_illumorae

then restart. The repo's layout means every node is self-contained - if you only want this one, copy just ComfyUI_illumorae_ControlnetImagePreprocessCached/ into custom_nodes and delete the rest.

Python-side nothing exotic: numpy, pillow, opencv-python, scipy, safetensors, transformers, huggingface-hub, torchvision.

The real download happens on first use. LineArt and LeReS pull weights from lllyasviel/Annotators on HuggingFace through huggingface_hub at execution time: sk_model.pth and sk_model2.pth for lineart, res101.pth plus a pix2pix pair for LeReS. Canny needs nothing. So keep huggingface_hub installed, and don't be surprised when the first LeReS run takes minutes with a quiet console - the node rebuilds its detector on every cache miss, which is exactly why the cache is worth having.

Where people get burned

A cache that never hits. Nine times out of ten it's the path: a file path that doesn't exist, a source_name given with its extension, or - very common in Docker or on a remote box - a host path the ComfyUI process can't see. Use the path as the process sees it. With debug on, the console prints the resolved source and cache paths, which tells you immediately which one it is.

A cache that won't refresh. If you replace the source image while preserving its timestamp (a cp -p, a git checkout, some sync tools), the mtime comparison sees nothing new. Bump force_refresh, or pass a timestamp in source_date_modified to override the file's mtime entirely - that field exists for sources whose timestamps you don't trust.

Reading the pack's README as documentation for this node. It doesn't mention the ControlNet preprocessor at all - it predates it. controlnet_image_preprocess_cached.py is the authority, defaults included.

Categoryillumorae

Inputs (15)

NameTypeDefaultDescription
source_pathSTRING
preprocessorCOMBO3 options: canny, leres, lineart
update_cache_if_newerBOOLEANtrue
force_refreshBOOLEANfalse
imageoptIMAGE
source_nameoptSTRING
source_date_modifiedoptFLOAT00–1000000000000
debugoptBOOLEANfalse
low_thresholdoptFLOAT0.150–1
high_thresholdoptFLOAT0.300–1
coarseoptFLOAT1.00–10
resolutionoptINT51264–8192
rm_nearestoptFLOAT0.00–100
rm_backgroundoptFLOAT0.00–100
boostoptCOMBO2 options: disable, enable

Outputs (2)

NameTypeDescription
imageIMAGE
cache_hitBOOLEAN