Extract Black Advanced
When plain Extract Black isn't enough — luminance, saturation, and three output modes
- image
- image
Plain Extract Black decides "black" by looking at the raw RGB channels. Extract Black Advanced is the version that stops being fooled: it judges darkness by perceived luminance - 0.299·R + 0.587·G + 0.114·B, the same weighting your eyes apply - and refuses to call something black if it's actually a dark color rather than a dark gray. That distinction matters a lot more than it sounds like. A dark navy line and a black line can have nearly identical channel values, and the naive node will happily lump them together. Advanced separates them, then gives you three output modes for how to render the result.
How it works
A pixel is kept as black when two things are true: its luminance is below luminance_threshold (default 0.2), and its saturation is below saturation_tolerance (default 0.3). Saturation is computed as the channel spread divided by the max channel, so a saturated dark blue gets rejected as "colored" while a flat dark gray passes. It's the same luminance-versus-saturation logic that defines "black" in color theory, and it's exactly the right tool for scanned ink that's actually a very dark hue.
Then output_mode picks the rendering:
black_on_white(default) - black linework on a white background.white_on_black- inverted, for consumers that want light lines on dark.preserve_black_values- keeps each pixel's original dark value instead of flattening to pure black. Gentler, and a good choice if the next node cares about stroke shading.
The apply_antialiasing toggle (default on) is worth understanding. When on, pixels in the gray transition band between line and background get converted to their luminance value as grayscale instead of hard-flipping to white or black. That preserves soft edges, which makes measured line lengths and downstream skeletonization more faithful. Turn it off if you want a hard, clean mask with no gray anywhere.
The settings that bite
luminance_threshold is the one you'll actually tune. Raise it past 0.3–0.4 and you start absorbing gray shadows and paper texture into the "lines." Lower it and faint pencil strokes drop out. saturation_tolerance at 0.3 is permissive enough for most scans; if colored fills keep leaking through as black, drop it toward 0.1. When in doubt, run it once with preserve_black_values and eyeball the result before switching to the harsher modes.
Install & context
Part of ComfyUI-HappNodeSet by mikemojen. Manager: search HappNodeSet. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/mikemojen/ComfyUI-HappNodeSet.git
pip install -r ComfyUI-HappNodeSet/requirements.txt
Restart ComfyUI. The heavy lifting here is torch + OpenCV + scikit-image, all pack-standard deps you almost certainly already have.
Honest take: for a clean scan, Extract Black with a nudged threshold gives you 90% of the result with one slider. Reach for Advanced when your source has colored darks, gray halftones, or anti-aliasing you care about preserving - that's the case where its extra machinery earns its keep. And like every node in this cleanup family, preview the output before you trust whatever line counter you've got downstream; the whole pack assumes clean input, and this is the node that produces it.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| luminance_threshold | FLOAT | 0.200–1 | Pixels with luminance below this threshold are considered black |
| saturation_tolerance | FLOAT | 0.300–1 | Maximum saturation allowed for a pixel to be considered black (allows dark grays) |
| output_modeopt | COMBO | 3 options: black_on_white, white_on_black, preserve_black_values | |
| apply_antialiasingopt | BOOLEAN | true | Preserve anti-aliasing by keeping grayscale values for edge pixels |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |