Better grading of the jumpsuit
This commit is contained in:
@@ -140,6 +140,7 @@ Keylight-style color-difference keyer) with a `color_grade` step. Key fields:
|
||||
| `despill_bias` | RGB the keyed *edges* shift toward. A light neutral/skin tone reads better than cool blue. |
|
||||
| `despill_strength` | How hard the edge/dominant-green despill pulls toward `despill_bias`. |
|
||||
| `spill_suppress` | **Interior green-limiter — see below.** |
|
||||
| `yellow_protect` | Shields saturated yellows/warm fabrics from `spill_suppress` (0–1). |
|
||||
| `edge_erode` | Shrinks the alpha edge by N passes to kill green fringe (0–5). |
|
||||
|
||||
**`spill_suppress` — the bald-head knob.** The regular despill only acts where
|
||||
@@ -158,6 +159,14 @@ Green is only ever *reduced*, never boosted, so clean pixels are untouched.
|
||||
Start around `0.6`; go past `1.0` for heavy close-up spill. If skin tips
|
||||
magenta/pink, ease back down. Range is `0.0`–`2.0`.
|
||||
|
||||
**`yellow_protect` — keep yellows yellow.** Because `spill_suppress` caps green
|
||||
*everywhere*, it also drains green from things that are legitimately yellow (a
|
||||
yellow jumpsuit, warm props), turning them orange. Blue is the tell: skin keeps
|
||||
some blue, saturated yellow fabric reflects almost none. `yellow_protect`
|
||||
(0.0–1.0) gates the green-limiter back down where `min(r,g) − b` is high
|
||||
(yellow) while leaving skin/scalp spill fully suppressed. Bump it toward `1.0`
|
||||
if warm colours go orange; leave at `0` if you have no strong yellows.
|
||||
|
||||
#### Grade preview (`grade`)
|
||||
|
||||
Iterate on keying/grading without running a full preprocess. It seeks a few
|
||||
|
||||
@@ -140,6 +140,14 @@ class GnommoKeyConfig:
|
||||
# close-up spill (2.0 = green can never exceed the smallest channel).
|
||||
spill_suppress: float = 0.0
|
||||
|
||||
# Protect saturated yellows/warm fabrics from spill_suppress (0.0-1.0, 0 = off).
|
||||
# spill_suppress caps green everywhere, which turns legit yellow (high r+g,
|
||||
# low b) into orange. Blue is the tell: skin keeps some blue, yellow fabric
|
||||
# reflects almost none. This gates the green-limiter down where
|
||||
# min(r,g)-b is high (yellow) while leaving skin/scalp spill fully suppressed.
|
||||
# 1.0 = full protection for strong yellows. Only matters when spill_suppress>0.
|
||||
yellow_protect: float = 0.0
|
||||
|
||||
# Alpha bias: influences edge treatment (RGB)
|
||||
# Can help with edge color contamination
|
||||
alpha_bias: tuple[int, int, int] = None
|
||||
|
||||
+20
-2
@@ -1215,13 +1215,30 @@ def build_gnommokey_filter(config: dict) -> str:
|
||||
# boosted, so non-spilled pixels are untouched.
|
||||
if cfg.spill_suppress > 0:
|
||||
t = min(max(cfg.spill_suppress, 0.0), 2.0)
|
||||
yp = min(max(cfg.yellow_protect, 0.0), 1.0)
|
||||
|
||||
def _protected(spill_ch: str, capped: str, warm_ch: str, cold_ch: str) -> str:
|
||||
"""Blend the capped spill channel back toward its original value for
|
||||
saturated hues that legitimately pair the spill channel with a warm
|
||||
channel while the cold channel is low (e.g. yellow = green+red, no
|
||||
blue). Skin/scalp keeps some cold channel, so it stays suppressed."""
|
||||
if yp <= 0:
|
||||
return capped
|
||||
# "yellowness": high when spill & warm are both high but cold is low.
|
||||
hue = f"max(0,min({spill_ch},{warm_ch})-{cold_ch})"
|
||||
gate = f"clip(({hue}-40)/120,0,1)"
|
||||
protect = f"({gate}*{yp:.3f})"
|
||||
return f"({spill_ch}*{protect}+({capped})*(1-{protect}))"
|
||||
|
||||
if is_green_screen:
|
||||
ref = f"((1-{t:.3f})*max(r(X,Y),b(X,Y))+{t:.3f}*(r(X,Y)+b(X,Y))/2)"
|
||||
new_g = f"min(g(X,Y),{ref})"
|
||||
capped = f"min(g(X,Y),{ref})"
|
||||
new_g = _protected("g(X,Y)", capped, "r(X,Y)", "b(X,Y)")
|
||||
parts.append(f"geq=r='r(X,Y)':g='{new_g}':b='b(X,Y)':a='alpha(X,Y)'")
|
||||
else:
|
||||
ref = f"((1-{t:.3f})*max(r(X,Y),g(X,Y))+{t:.3f}*(r(X,Y)+g(X,Y))/2)"
|
||||
new_b = f"min(b(X,Y),{ref})"
|
||||
capped = f"min(b(X,Y),{ref})"
|
||||
new_b = _protected("b(X,Y)", capped, "r(X,Y)", "g(X,Y)")
|
||||
parts.append(f"geq=r='r(X,Y)':g='g(X,Y)':b='{new_b}':a='alpha(X,Y)'")
|
||||
|
||||
# Edge-aware despill: aggressively suppress green at semi-transparent edges
|
||||
@@ -1311,6 +1328,7 @@ def parse_gnommokey_config(config: dict) -> GnommoKeyConfig:
|
||||
despill_bias=despill_bias,
|
||||
despill_strength=float(config.get("despill_strength", 0.5)),
|
||||
spill_suppress=float(config.get("spill_suppress", 0.0)),
|
||||
yellow_protect=float(config.get("yellow_protect", 0.0)),
|
||||
alpha_bias=alpha_bias,
|
||||
protect_luma=int(config.get("protect_luma", -1)),
|
||||
shadow_boost=float(config.get("shadow_boost", 0.0)),
|
||||
|
||||
Reference in New Issue
Block a user