Lineart (Soze)
Sobel lineart without OpenCV — cleaner control, no model downloads
- image
- image
- mask
- status
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;maxandnoneare 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.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| pre_blur_sigma | FLOAT | 0.500–10 | Gaussian denoise before Sobel. 0 = none. Higher hides texture noise. |
| line_strength | FLOAT | 1.00.1–10 | Multiplier on the gradient magnitude before normalize / threshold. |
| normalize | COMBO | percentile_95 | How to map raw gradient magnitude to [0,1]. percentile_95 is robust to outliers. |
| gamma | FLOAT | 1.000.1–5 | Output gamma. <1 darkens lines, >1 brightens / spreads them. |
| soft_threshold | FLOAT | 0.000–1 | Continuous noise gate — anything below this drops to 0. 0 = off. |
| thickness | INT | 00–10 | Morphological dilation iterations. 0 = thin / native; each step adds ~1 pixel of line width. |
| thinning | BOOLEAN | false | Apply one erosion pass before any thickening (skeleton-ish). |
| binarize | BOOLEAN | false | Hard black/white using binarize_threshold. |
| binarize_threshold | FLOAT | 0.500–1 | Only used when binarize=True. |
| invert | BOOLEAN | false | Off: white lines on black (ControlNet convention). On: black lines on white (sketch preview). |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| status | STRING | — |