ComfyUI Node
BD Center Median Luma
Compute the luma MEDIAN of the (optionally masked) input pixels, then ADD a constant offset so that median lands exactly on target_center. Preserves histogram shape (spread/contrast unchanged), only shifts position. Why: V-curve skin shaders need the input's median to sit AT the midpoint (u_float0) for tint to dominate. BD_NormalizeLuma controls spread; this node controls POSITION. Use both: normalize first (set spread), then center (set median position), then feed u_image0.
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►
Category🧠BrainDead/Segmentation
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Source image (single or batch). Each frame is centered independently. | |
| luma_standard | COMBO | bt709 | RGB → 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_center | FLOAT | 0.500–1 | Desired median luma after centering. Set to your V-curve midpoint (u_float0). Default 0.5 keeps things symmetric. |
| statistic | COMBO | median | median = 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_mask | BOOLEAN | true | Controls 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_only | BOOLEAN | true | Controls 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_transparent | BOOLEAN | true | When 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_alpha | BOOLEAN | true | ON: alpha channel passes through unchanged. OFF: alpha is also shifted (rarely what you want). |
| maskopt | MASK | Optional 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)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | Centered image (RGB shifted by the same constant). |
| measured_median | FLOAT | The actual masked-luma median found in the input. Useful for debugging or wiring to another node. |
| shift_applied | FLOAT | The constant added to RGB. = target_center - measured_median. Negative if input was too bright, positive if too dark. |