def texture_mask(
clip: vs.VideoNode, rady: int = 2, radc: int | None = None,
blur: int | float = 8, thr: float = 0.2,
stages: list[tuple[int, int]] = [(60, 2), (40, 4), (20, 2)],
points: list[tuple[bool, float]] = [(False, 1.75), (True, 2.5), (True, 5), (False, 10)]
) -> ConstantFormatVideoNode:
levels = [x for x, _ in points]
_points = [scale_value(x, 8, clip) for _, x in points]
thr = scale_value(thr, 8, 32, ColorRange.FULL)
qm, peak = len(points), get_peak_value(clip)
rmask = MinMax(rady, fallback(radc, rady)).edgemask(clip, lthr=0)
emask = clip.std.Prewitt()
rm_txt = ExprOp.MIN(rmask, (
Morpho.minimum(Morpho.binarize(emask, thr, 1.0, 0), iterations=it)
for thr, it in stages
))
expr = [f'x {_points[0]} < x {_points[-1]} > or 0']
for x in range(len(_points) - 1):
if _points[x + 1] < _points[-1]:
expr.append(f'x {_points[x + 1]} <=')
if levels[x] == levels[x + 1]:
expr.append(f'{peak if levels[x] else 0}')
else:
mean = peak * (levels[x + 1] - levels[x]) / (_points[x + 1] - _points[x])
expr.append(f'x {_points[x]} - {mean} * {peak * levels[x]} +')
weighted = norm_expr(rm_txt, [expr, ExprOp.TERN * (qm - 1)], func=texture_mask)
if isinstance(blur, float):
weighted = gauss_blur(weighted, blur)
else:
weighted = box_blur(weighted, blur)
return norm_expr(weighted, f'x {peak * thr} - {1 / (1 - thr)} *', func=texture_mask)