Nodes/BrainDead Nodes/BD Center Median Luma
ComfyUI Node

BD Center Median Luma

Make your skin shader's median sit dead-center — the V-curve fix

By BizaNator·Created 8 months ago·Updated 3 days ago· 15
BD Center Median Luma
  • image
  • mask
  • image
  • measured_median
  • shift_applied
luma_standardbt709
target_center0.50
statisticmedian
calc_from_masktrue
apply_to_mask_onlytrue
exclude_transparenttrue
preserve_alphatrue

Some shaders are picky about where your image's brightness sits. The V-curve skin shaders this pack's GLSL pipeline targets assume the input's median luma lands at the curve's midpoint - the u_float0 uniform - so the tint dominates evenly across shadows and highlights. Real generated images don't cooperate; a face that reads too dark overall pushes the median off-center and the whole tint lands wrong. BD Center Median Luma fixes the position: it computes the luma median of your input, then adds a single constant offset so the median lands exactly on your target_center. The node description is precise about what it does and doesn't do: it preserves the histogram shape (spread and contrast unchanged) and only shifts position. No contrast remap, no tone curve - a straight additive shift.

This is deliberately the other half of a two-node pair. BD Normalize Luma controls the spread (range); this node controls the position (median). The description says it plainly: normalize first to set the spread, then center to set the median position, then feed the result to the shader.

The inputs that matter

  • image - the source, single or batch. Each frame is centered independently.
  • mask - strongly recommended. The median should be measured from the subject, not the background. Without a mask, background pixels bias the measurement. Wire a skin or body mask here and the defaults handle the rest.
  • target_center - where the median should land, default 0.5. Set it to your V-curve midpoint (u_float0).
  • luma_standard - the RGB→luma weights: bt709 (default, modern sRGB/Rec.709, right for Unity/Unreal), bt601 (legacy NTSC, matches Photoshop Desaturate), or average. Pick bt709 unless you have a specific reason not to.
  • statistic - median (default) is robust to cheek highlights and deep shadows; mean is smoother but outlier-sensitive. Median is the right call for V-curve centering.
  • calc_from_mask - which pixels are used to measure. ON (default) measures mask pixels only. OFF measures the whole image, with exclude_transparent as a fallback for images that already carry a body-shaped alpha.
  • apply_to_mask_only - where the shift is applied. ON (default) shifts only within the mask, leaving the background untouched. OFF shifts everything.

Those last two are independent, and the combos are worth a moment: you can measure from the mask but apply to the whole image, or measure the whole image and apply only in the mask. The defaults (measure and apply in-mask) are right for most cases.

Outputs: image (the centered result), measured_median (FLOAT, what the input's median actually was), and shift_applied (FLOAT, the offset added - negative if the input was too bright, positive if too dark). Both floats are great for wiring into diagnostics or feeding the shader's uniform directly.

Installing it

Part of BizaNator/ComfyUI-BrainDead (BrainDeadGuild). ComfyUI Manager → search "BrainDead" → install, or:

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

Restart; it's under 🧠BrainDead/Segmentation.

Gotchas

The classic failure is skipping the mask. Without it, a dark or bright background drags the measured median off, and the "centered" result is still off-center - because the shift was calibrated on the wrong population. If your source already has a proper alpha, calc_from_mask=OFF + exclude_transparent=True is the honest fallback. Second: this node shifts position only. If your image is also too flat or too contrasty, center it and then normalize the spread - or the other way around; the order matters less than doing both. And one subtlety: if your shader expects a mean rather than a median, flip the statistic - the two disagree exactly when your image has outlier highlights, which skin often does.

Category🧠BrainDead/Segmentation

Inputs (9)

NameTypeDefaultDescription
imageIMAGESource image (single or batch). Each frame is centered independently.
luma_standardCOMBObt709RGB → luminance weighting: bt709 (default): 0.2126 R + 0.7152 G + 0.0722 B — modern sRGB/Rec.709 standard. Use for Unity/Unreal, AI pipelines, modern display work. bt601: 0.299 R + 0.587 G + 0.114 B — legacy NTSC weights, matches Photoshop 'Desaturate' and older tools. average: (R+G+B)/3 — simple, not perceptual.
target_centerFLOAT0.500–1Desired median luma after centering. Set to your V-curve midpoint (u_float0). Default 0.5 keeps things symmetric.
statisticCOMBOmedianmedian = robust to outliers (cheek highlights, deep shadows). mean = sensitive to outliers but gives a smoother shift. Median is the right default for V-curve centering.
calc_from_maskBOOLEANtrueControls which pixels are used to MEASURE the median. ON (default): median is computed from mask pixels only (where mask > 0.5). Recommended — background doesn't bias. OFF: median is computed from the whole image. Use with exclude_transparent to skip fully-transparent background pixels (e.g. when the source already has a body-shape alpha). Independent from apply_to_mask_only — you can measure from the mask but apply the shift to the whole image, or vice versa. Has no effect when no mask is wired.
apply_to_mask_onlyBOOLEANtrueControls WHERE the computed shift is APPLIED. ON (default): only pixels WITHIN the mask are shifted; pixels outside pass through unchanged. OFF: the shift is applied to the whole image. Independent from calc_from_mask — common combinations: calc_from_mask=ON, apply=mask → measure+apply in mask only calc_from_mask=ON, apply=whole → measure mask, shift entire image calc_from_mask=OFF, apply=mask → measure whole image, apply in mask calc_from_mask=OFF, apply=whole → whole-image both (mask irrelevant) Has no effect when no mask is wired.
exclude_transparentBOOLEANtrueWhen calc_from_mask is OFF (measuring from whole image), exclude pixels where the source alpha < 0.5 from the median calculation. Prevents a fully-transparent background from biasing the median when the source already has a body/head alpha. Ignored when calc_from_mask is ON, or when the image has no alpha channel.
preserve_alphaBOOLEANtrueON: alpha channel passes through unchanged. OFF: alpha is also shifted (rarely what you want).
maskoptMASKOptional region mask (e.g. skin mask). Used for calculation and/or application depending on calc_from_mask / apply_to_mask_only. STRONGLY RECOMMENDED — without a mask, background pixels bias the median (use exclude_transparent as a fallback).

Outputs (3)

NameTypeDescription
imageIMAGECentered image (RGB shifted by the same constant).
measured_medianFLOATThe actual masked-luma median found in the input. Useful for debugging or wiring to another node.
shift_appliedFLOATThe constant added to RGB. = target_center - measured_median. Negative if input was too bright, positive if too dark.