ComfyUI Node

Lineart (Soze)

Sobel lineart without OpenCV — cleaner control, no model downloads

By SozeInc·Created 2 years ago·Updated 8 days ago· 10
Lineart (Soze)
  • image
  • image
  • mask
  • status
pre_blur_sigma0.50
line_strength1.0
normalizepercentile_95
gamma1.00
soft_threshold0.00
thickness0
thinningfalse
binarizefalse
binarize_threshold0.50
invertfalse

Lineart preprocessors are a ControlNet staple - they turn a photo into clean outlines that a model can follow, and they're a favorite for character consistency, where line structure plus a reference image keeps a character recognizable across scenes. Lineart (Soze) does the extraction without any OpenCV dependency: a pure-PyTorch Sobel-gradient pipeline with a pile of tuning knobs, plus a mask output most preprocessors don't give you. No model files, no downloads - it just runs.

If you've used ControlNet lineart before, you know the convention: the preprocessor outputs white lines on a black background, and that's exactly what this node produces by default. Flick invert and you get black lines on white - the sketch-preview look, and the form some models and workflows expect. It's the sibling of the same pack's Scribble XDoG node; different algorithm (gradient-based vs. DoG), same general job of extracting line structure.

How it works

The pipeline, in order: convert to grayscale → optional Gaussian pre-blur → 3×3 Sobel gradient magnitude → optional strength multiplier → normalize to [0,1] → optional noise gate → gamma → optional morphology → optional binarize → optional invert. Because it's pure torch, it runs on whatever device ComfyUI is using, and it processes whole batches frame by frame.

The controls that matter most:

  • pre_blur_sigma - Gaussian denoise before the Sobel. 0 = none. Higher values hide texture noise. If your lineart looks like static, this is the first knob to raise.
  • line_strength - multiplier on the gradient magnitude before normalization. Crank it to make faint lines visible.
  • normalize - how the raw gradient is mapped to [0,1]. percentile_95 (default) anchors the 95th percentile to 1.0, which is robust to bright outliers; max and none are the alternatives.
  • soft_threshold - a continuous noise gate: anything below this drops to zero, above is kept. 0 = off. It's the "clean it up" control that doesn't force hard edges.
  • thickness / thinning - morphological dilation iterations (each adds ~1px of line width) and an optional erosion pass for a skeleton-ish look.
  • binarize + binarize_threshold - hard black/white output when you want the strictest lines.
  • invert - white-on-black (ControlNet convention) or black-on-white.

Inputs and outputs

  • image - required IMAGE (handles batches; RGBA is handled by dropping alpha).

Outputs: image (the lineart, [B,H,W,3]), mask (the same lines as a single-channel MASK - the freebie that lets you use lineart as a mask for inpainting or compositing without an extra node), and status (STRING summarizing settings and frame count).

Installing it

Part of the Soze pack:

cd ComfyUI/custom_nodes
git clone https://github.com/SozeInc/ComfyUI_Soze.git
pip install -r ComfyUI_Soze/requirements.txt

Restart ComfyUI, or search ComfyUI_Soze in ComfyUI Manager. Zero model downloads - this is the whole appeal versus downloading a dedicated ControlNet lineart preprocessor model.

Where people get burned

The most common complaint with lineart preprocessors in general is weak or noisy output, and here the fix is usually pre_blur_sigma up a notch and soft_threshold just above the noise floor - not binarize, which is harsh. Lineart as a conditioning is softer than Canny (good for style and character work, weaker for strict edge fidelity), so don't expect it to hold geometry the way Canny does. And if your ControlNet setup seems to ignore it entirely, that's usually a strength or model issue on the ControlNet side, not the preprocessing - the node's status string confirms the lines were actually produced before you go chasing the rest of the graph.

Categoryimage/preprocessors

Inputs (11)

NameTypeDefaultDescription
imageIMAGE
pre_blur_sigmaFLOAT0.500–10Gaussian denoise before Sobel. 0 = none. Higher hides texture noise.
line_strengthFLOAT1.00.1–10Multiplier on the gradient magnitude before normalize / threshold.
normalizeCOMBOpercentile_95How to map raw gradient magnitude to [0,1]. percentile_95 is robust to outliers.
gammaFLOAT1.000.1–5Output gamma. <1 darkens lines, >1 brightens / spreads them.
soft_thresholdFLOAT0.000–1Continuous noise gate — anything below this drops to 0. 0 = off.
thicknessINT00–10Morphological dilation iterations. 0 = thin / native; each step adds ~1 pixel of line width.
thinningBOOLEANfalseApply one erosion pass before any thickening (skeleton-ish).
binarizeBOOLEANfalseHard black/white using binarize_threshold.
binarize_thresholdFLOAT0.500–1Only used when binarize=True.
invertBOOLEANfalseOff: white lines on black (ControlNet convention). On: black lines on white (sketch preview).

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
statusSTRING