regress ¶
This module provides utilities for chroma reconstruction using local linear regression.
Most of this is based on the work of doop, originally written for Irozuku Sekai no Ashita kara.
Classes:
-
ChromaReconstruct–Abstract base class for chroma reconstruction via regression.
Functions:
-
reconstruct–Reconstruct a predicted clip from regression results.
-
regression–Perform per-pixel linear regression between a reference clip
xand one or more target clipsys,
ChromaReconstruct dataclass ¶
ChromaReconstruct(
luma_base: VideoNode, chroma_bases: Sequence[VideoNode], clip_src: VideoNode
)
Bases: VSObjectABC
Abstract base class for chroma reconstruction via regression.
Provides an interface for reconstructing chroma planes from luma using linear regression, with support for chroma demangling/mangling depending on chroma siting.
Subclasses must at least implement
- A
mangle_lumamethod - Either
demangle_lumaanddemangle_chroma, or a singledemanglemethod handling all planes.
Example
Consider the show Sirius the Jaeger, produced by P.A. Works, known for chroma mangling in some titles. Several steps are required to reconstruct the chroma planes:
- Choose the appropriate luma base plane (usually descaled to the production resolution).
- Determine how the chroma planes were mangled during production.
For Sirius, originally produced at 720p, the chroma planes underwent:
- Produced at 1280x720 4:4:4.
- Downscaled to 640x720 4:2:2 with point resize.
- Resized to 960x540 with point resize (width) and neutral downscaling (height, e.g. Catrom).
A custom subclass may then be defined:
from vskernels import BorderHandling, Catrom, Lanczos
from vstools import depth, split
class SiriusReconstruct(ChromaReconstruct):
catrom = Catrom()
def mangle_luma(self, luma_base: vs.VideoNode) -> vs.VideoNode:
# Input: descaled luma plane (1280x720).
# Align as if it were subsampled, matching the chroma path.
return core.resize.Point(luma_base, 640, 720, src_left=-1).resize.Point(960, 720, src_left=-0.25)
def demangle(self, clip: vs.VideoNode) -> vs.VideoNode:
# Input: luma 960x720 or chroma 960x540.
# Undo the width point-resize.
clip = core.resize.Point(clip, 640, clip.height)
# Rescale to 1280x540. Since only vertical downscaling is needed,
# this avoids blurring chroma by upscaling vertically.
return self.catrom.scale(clip, 1280, 540, self.ss_shift.to_full())
def base_for_reconstruct(self, luma_base: vs.VideoNode, demangled_luma: vs.VideoNode) -> vs.VideoNode:
# `demangle` outputs 1280x540, so downscale luma_base accordingly.
# Better to downscale luma here than to upscale chroma vertically.
return self.catrom.scale(luma_base, height=540)
clip = depth(clip, 32, vs.FLOAT)
y, u, v = split(clip)
descaled_y = Lanczos(3).descale(y, 1280, 720, border_handling=BorderHandling.ZERO)
recon = SiriusReconstruct(descaled_y, [u, v], clip)
recon.regression(radius=4)
chroma_recon = recon.reconstruct(radius=4)
The reconstruct method outputs reconstructed chroma planes at the same resolution returned by demangle. From here, you may:
- Downscale to obtain a 4:2:0 clip (recommended).
- Upscale to produce a 1080p 4:4:4 clip.
- Combine with the descaled luma for a 720p 4:4:4 clip (requires upscaling chroma vertically).
Example: downscale reconstructed chroma to 4:2:0:
from vskernels import Hermite
from vsscale import ArtCNN
from vstools import join
rescaled_y = ArtCNN.R8F64(scaler=Hermite(linear=True)).scale(descaled_y, 1920, 1080)
merged = join(
[
rescaled_y,
*(Hermite().scale(c, 960, 540, recon.ss_shift.to_subsampled(c, (960, 540))) for c in chroma_recon),
]
)
Initialize chroma reconstruction.
Parameters:
-
(luma_base¶VideoNode) –Luma base plane (float GRAY).
-
(chroma_bases¶Sequence[VideoNode]) –Chroma base planes (float GRAY).
-
(clip_src¶VideoNode) –Source clip from which to derive chroma location.
Raises:
-
UnsupportedVideoFormatError–If any base clip is not GRAY float format.
Methods:
-
base_for_reconstruct–Optionally resize or adjust luma before reconstructing.
-
demangle–Demangle a plane (luma or chroma).
-
demangle_chroma–Demangle a chroma plane.
-
demangle_luma–Demangle a luma plane.
-
mangle_luma–Mangle the luma base plane before regression.
-
reconstruct–Reconstruct chroma planes using regression results.
-
regression–Perform per-pixel regression between demangled luma and chroma planes.
-
ss_shift–Helper for handling chroma subsampling shifts.
Attributes:
-
chroma_bases(Sequence[VideoNode]) –The chroma base planes.
-
chroma_loc(ChromaLocation) –Chroma location derived from the source clip.
-
clip_src(ConstantFormatVideoNode) –The original source clip.
-
luma_base(VideoNode) –The luma base plane.
Source code in vsrgtools/regress.py
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | |
chroma_bases instance-attribute ¶
chroma_bases: Sequence[VideoNode] = chroma_bases
The chroma base planes.
chroma_loc class-attribute instance-attribute ¶
chroma_loc: ChromaLocation = from_video(clip_src, True, __class__)
Chroma location derived from the source clip.
clip_src instance-attribute ¶
clip_src: ConstantFormatVideoNode = clip_src
The original source clip.
base_for_reconstruct ¶
base_for_reconstruct(
luma_base: VideoNode, demangled_luma: VideoNode
) -> VideoNode
Optionally resize or adjust luma before reconstructing.
By default, returns the luma base unchanged.
Parameters:
-
(luma_base¶VideoNode) –Original luma base plane.
-
(demangled_luma¶VideoNode) –Demangled luma plane.
Returns:
-
VideoNode–Adjusted luma base plane.
Source code in vsrgtools/regress.py
553 554 555 556 557 558 559 560 561 562 563 564 565 566 | |
demangle ¶
demangle(clip: VideoNode) -> VideoNode
Demangle a plane (luma or chroma).
Applies the inverse of mangling to recover aligned planes for regression.
Parameters:
-
(clip¶VideoNode) –Plane to demangle.
Returns:
-
VideoNode–Demangled plane.
Raises:
-
NotImplementedError–If not implemented in subclass.
Source code in vsrgtools/regress.py
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | |
demangle_chroma ¶
demangle_chroma(chroma_mangled: VideoNode) -> VideoNode
Demangle a chroma plane.
Applies the inverse of mangling to recover aligned chroma for regression.
Parameters:
-
(chroma_mangled¶VideoNode) –Chroma plane to demangle.
Returns:
-
VideoNode–Demangled chroma plane.
Source code in vsrgtools/regress.py
539 540 541 542 543 544 545 546 547 548 549 550 551 | |
demangle_luma ¶
demangle_luma(luma_mangled: VideoNode) -> VideoNode
Demangle a luma plane.
Applies the inverse of mangling to recover aligned luma for regression.
Parameters:
-
(luma_mangled¶VideoNode) –Luma plane to demangle.
Returns:
-
VideoNode–Demangled luma plane.
Source code in vsrgtools/regress.py
525 526 527 528 529 530 531 532 533 534 535 536 537 | |
mangle_luma abstractmethod ¶
mangle_luma(luma_base: VideoNode) -> VideoNode
Mangle the luma base plane before regression.
This may adjust resolution or siting. The resolution does not need to match the chroma planes.
Parameters:
-
(luma_base¶VideoNode) –Luma base plane.
Returns:
-
VideoNode–Mangled luma plane.
Raises:
-
NotImplementedError–If not implemented in subclass.
Source code in vsrgtools/regress.py
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | |
reconstruct ¶
reconstruct(
radius: int = 1,
mean: MeanMode | MeanFunction = lambda c, radius: box_blur(
c, radius, mode=HV
),
**kwargs: Any
) -> Sequence[VideoNode]
Reconstruct chroma planes using regression results.
Must be called after regression.
Parameters:
-
(radius¶int, default:1) –Neighborhood radius for smoothing regression coefficients.
-
(mean¶MeanMode | MeanFunction, default:lambda c, radius: box_blur(c, radius, mode=HV)) –Function or mode used to compute local means. Defaults to box blur.
-
(**kwargs¶Any, default:{}) –Forwarded to reconstruct.
Raises:
-
CustomRuntimeError–If regression has not been called first.
-
FormatsRefClipMismatchError–If luma formats mismatch.
-
ResolutionsRefClipMismatchError–If luma resolutions mismatch.
Returns:
-
Sequence[VideoNode]–Sequence of reconstructed chroma planes.
Source code in vsrgtools/regress.py
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | |
regression ¶
regression(
radius: int = 1,
mean: MeanMode | MeanFunction = lambda c, radius: box_blur(
c, radius, mode=HV
),
alpha: float = 0.2,
**kwargs: Any
) -> Sequence[RegressClips]
Perform per-pixel regression between demangled luma and chroma planes.
Uses local neighborhoods to estimate slopes, intercepts, and correlations.
Parameters:
-
(radius¶int, default:1) –Neighborhood radius for mean/variance estimates. Must be > 0.
-
(mean¶MeanMode | MeanFunction, default:lambda c, radius: box_blur(c, radius, mode=HV)) –Function or mode used to compute local means. Defaults to box blur.
-
(alpha¶float, default:0.2) –Significance/confidence level for reliability weighting. Defaults to 0.20.
-
(**kwargs¶Any, default:{}) –Forwarded to regression.
Raises:
-
FormatsRefClipMismatchError–If luma and chroma demangled planes differ in format.
-
ResolutionsRefClipMismatchError–If luma and chroma demangled planes differ in resolution.
Returns:
-
Sequence[RegressClips]–Sequence of RegressClips, one for each chroma plane.
Source code in vsrgtools/regress.py
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | |
ss_shift ¶
ss_shift() -> SubsampledShift
Helper for handling chroma subsampling shifts.
Returns:
-
SubsampledShift(SubsampledShift) –A helper object for chroma siting/offsets.
Source code in vsrgtools/regress.py
678 679 680 681 682 683 684 685 686 | |
MeanFunction ¶
RegressClips ¶
Bases: NamedTuple
Results of per-pixel linear regression between one clip (x) and another (y).
Attributes:
-
correlation(VideoNode) –Correlation coefficient.
-
intercept(VideoNode | None) –Regression intercept.
-
slope(VideoNode) –Regression slope.
SubsampledShift ¶
SubsampledShift(chroma_location: ChromaLocation, fmt: VideoFormat)
Bases: VSObject
Utility class for handling chroma subsampling shifts.
Initializes the class.
Parameters:
-
(chroma_location¶ChromaLocation) –Chroma siting/positioning information.
-
(fmt¶VideoFormat) –Video format of the clip.
Methods:
-
to_full–Convert subsampled offsets to full-resolution (4:4:4) shift.
-
to_subsampled–Convert full-resolution offsets to subsampled coordinates.
Attributes:
Source code in vsrgtools/regress.py
301 302 303 304 305 306 307 308 309 310 311 312 313 314 | |
offsets property ¶
offsets: tuple[TopShift, LeftShift]
The raw vertical (top) and horizontal (left) chroma offsets.
to_full ¶
to_full() -> _Shift
Convert subsampled offsets to full-resolution (4:4:4) shift.
Assumes the source is subsampled (e.g. 4:2:0 or 4:2:2).
Returns:
-
_Shift–Vertical and horizontal shift scaled to full resolution.
Source code in vsrgtools/regress.py
316 317 318 319 320 321 322 323 324 325 | |
to_subsampled ¶
to_subsampled(
src_dim: tuple[Width, Height] | VideoNode,
dst_dim: tuple[Width, Height] | VideoNode,
) -> _Shift
Convert full-resolution offsets to subsampled coordinates.
Assumes the source is 4:4:4.
Parameters:
-
(src_dim¶tuple[Width, Height] | VideoNode) –Source dimensions or clip (treated as 4:4:4).
-
(dst_dim¶tuple[Width, Height] | VideoNode) –Destination dimensions or clip (subsampled).
Returns:
-
_Shift–Vertical and horizontal shift in subsampled coordinates.
Source code in vsrgtools/regress.py
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | |
fisher_weight ¶
Compute a reliability weight using Fisher's z-transformation.
The weight is inversely related to the confidence interval width in z-space: smaller confidence intervals indicate more reliable correlations.
Parameters:
-
(n¶int) –Sample size (must be > 3 for a meaningful result).
-
(alpha¶float) –Significance level for the two-tailed confidence interval.
Returns:
-
float–A weight in [0.0, 1.0], where larger values indicate higher reliability.
Source code in vsrgtools/regress.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | |
get_weight ¶
Select a reliability weight computation method.
Parameters:
-
(radius¶int) –Neighborhood radius used for regression. Determines sample size.
-
(alpha¶float) –Significance/confidence level for the statistical method.
-
(method¶str) –Weighting method, either "threshold" (t-based) or "fisher".
Returns:
-
float–A weight in [0.0, 1.0].
Raises:
-
CustomValueError–If
methodis not recognized.
Source code in vsrgtools/regress.py
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
reconstruct ¶
reconstruct(
clip: VideoNode,
r: RegressClips,
radius: int = 1,
mean: MeanMode | MeanFunction = lambda c, radius: box_blur(
c, radius, mode=HV
),
eps: float = 1e-07,
func: FuncExcept | None = None,
) -> VideoNode
Reconstruct a predicted clip from regression results.
Uses the regression slope, intercept (if available), and correlation to reconstruct the dependent variable from the input clip.
Parameters:
-
(clip¶VideoNode) –Input clip (independent variable).
-
(r¶RegressClips) –Regression results (slope, intercept, correlation).
-
(radius¶int, default:1) –Neighborhood radius for smoothing regression coefficients. Defaults to 1.
-
(mean¶MeanMode | MeanFunction, default:lambda c, radius: box_blur(c, radius, mode=HV)) –Function or mode used to compute local means. Defaults to box blur.
-
(eps¶float, default:1e-07) –Small constant to avoid division by zero. Defaults to 1e-7.
-
(func¶FuncExcept | None, default:None) –Optional function reference for error handling context.
Returns:
-
VideoNode–A new clip representing the reconstructed dependent variable.
Source code in vsrgtools/regress.py
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | |
regression ¶
regression(
x: VideoNode,
*ys: VideoNode,
radius: int = 1,
mean: MeanMode | MeanFunction = lambda c, radius: box_blur(
c, radius, mode=HV
),
alpha: float = 0.2,
weight_method: Literal["threshold", "fisher"] = "threshold",
intercept: float = False,
eps: float = 1e-07,
func: FuncExcept | None = None
) -> list[RegressClips]
Perform per-pixel linear regression between a reference clip x and one or more target clips ys, using local neighborhoods for mean/variance estimates.
More information
Each regression fits the model:
y ≈ x * slope + intercept
on a per-pixel basis, with slope, intercept (optional), and correlation computed over neighborhoods of size (2 * radius + 1)^2.
Parameters:
-
(x¶VideoNode) –Reference clip (independent variable).
-
(*ys¶VideoNode, default:()) –One or more clips to regress on
x(dependent variables). -
(radius¶int, default:1) –Neighborhood radius for mean/variance estimates. Must be > 0.
-
(mean¶MeanMode | MeanFunction, default:lambda c, radius: box_blur(c, radius, mode=HV)) –Function or mode used to compute local means. Defaults to box blur.
-
(alpha¶float, default:0.2) –Significance/confidence level for reliability weighting. Defaults to 0.20.
-
(weight_method¶Literal['threshold', 'fisher'], default:'threshold') –Method for computing reliability weight, "threshold" or "fisher".
-
(intercept¶float, default:False) –If True, compute regression intercepts. If False, intercepts are None.
-
(eps¶float, default:1e-07) –Small constant to avoid division by zero. Defaults to 1e-7.
-
(func¶FuncExcept | None, default:None) –An optional function to use for error handling.
Raises:
-
CustomValueError–If
radiusoralphaare out of bounds, or if an unknownweight_methodis provided.
Returns:
-
list[RegressClips]–A list of
RegressClips, one for each input clip inys, containing slope, intercept (or None), -
list[RegressClips]–and correlation.
Source code in vsrgtools/regress.py
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | |
t_based_weight ¶
Compute a reliability weight based on the t-distribution critical correlation.
The weight decreases with larger critical correlation thresholds (harder to reach significance) and increases with sample size.
Parameters:
-
(n¶int) –Sample size (must be > 3 for a meaningful result).
-
(alpha¶float) –Significance level for the two-tailed test.
Returns:
-
float–A weight in [0.0, 1.0], where larger values indicate higher reliability.
Source code in vsrgtools/regress.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |