soifunc 0.10.1__tar.gz → 0.11.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: soifunc
3
- Version: 0.10.1
3
+ Version: 0.11.0
4
4
  Summary: Soichiro's VapourSynth Functions Collection
5
5
  License: MIT
6
6
  Author: Josh Holmer
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3.13
13
13
  Requires-Dist: vapoursynth (>=68)
14
- Requires-Dist: vsjetpack (>=0.4.0,<0.5.0)
14
+ Requires-Dist: vsjetpack (>=0.5.1,<0.6.0)
15
15
  Description-Content-Type: text/markdown
16
16
 
17
17
  ## soifunc
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "soifunc"
3
- version = "0.10.1"
3
+ version = "0.11.0"
4
4
  description = "Soichiro's VapourSynth Functions Collection"
5
5
  authors = ["Josh Holmer <jholmer.in@gmail.com>"]
6
6
  license = "MIT"
@@ -9,7 +9,7 @@ readme = "README.md"
9
9
  [tool.poetry.dependencies]
10
10
  python = ">=3.12,<4.0"
11
11
  vapoursynth = ">=68"
12
- vsjetpack = "^0.4.0"
12
+ vsjetpack = "^0.5.1"
13
13
 
14
14
  [tool.poetry.group.dev.dependencies]
15
15
  black = "^25.1.0"
@@ -1,3 +1,4 @@
1
1
  from .deband import * # noqa: F401, F403
2
2
  from .denoise import * # noqa: F401, F403
3
+ from .interpolate import * # noqa: F401, F403
3
4
  from .resize import * # noqa: F401, F403
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from vsdeband import F3kdb
3
+ from vsdeband import f3k_deband
4
4
  from vsmasktools import dre_edgemask
5
5
  from vstools import InvalidVideoFormatError, check_variable, core, vs
6
6
 
@@ -19,7 +19,7 @@ def retinex_deband(
19
19
  16 might be a more sane starting point. Increase as needed.
20
20
 
21
21
  This function does not add grain on its own. Use another function like
22
- `vsdeband.sized_grain` to do that.
22
+ `vsdeband.AddNoise` to do that.
23
23
  """
24
24
  assert check_variable(clip, retinex_deband)
25
25
 
@@ -39,5 +39,5 @@ def retinex_deband(
39
39
  if showmask:
40
40
  return mask
41
41
 
42
- deband = F3kdb().deband(clip, thr=(threshold << 2))
42
+ deband = f3k_deband(clip, thr=(threshold << 2))
43
43
  return core.std.MaskedMerge(deband, clip, mask)
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from typing import Callable, Optional
4
4
 
5
5
  import vsdenoise
6
- from vsdenoise import DFTTest, FilterType, Profile, mc_degrain
6
+ from vsdenoise import DFTTest, bm3d, mc_degrain
7
7
  from vstools import core, vs
8
8
 
9
9
  __all__ = ["MCDenoise", "magic_denoise", "hqbm3d", "mc_dfttest"]
@@ -13,7 +13,7 @@ def hqbm3d(
13
13
  clip: vs.VideoNode,
14
14
  luma_str: float = 0.45,
15
15
  chroma_str: float = 0.4,
16
- profile: Profile = Profile.FAST,
16
+ profile: bm3d.Profile = bm3d.Profile.FAST,
17
17
  ) -> vs.VideoNode:
18
18
  """
19
19
  High-quality presets for motion compensated denoising.
@@ -24,24 +24,22 @@ def hqbm3d(
24
24
  blksize = select_block_size(clip)
25
25
  mv = mc_degrain(
26
26
  clip,
27
- preset=vsdenoise.MVToolsPresets.HQ_SAD,
27
+ preset=vsdenoise.MVToolsPreset.HQ_SAD,
28
28
  tr=2,
29
29
  thsad=100,
30
30
  refine=3 if blksize > 16 else 2,
31
31
  blksize=blksize,
32
32
  prefilter=vsdenoise.Prefilter.DFTTEST(
33
33
  clip,
34
- slocation=[(0.0, 1.0), (0.2, 4.0), (0.35, 12.0), (1.0, 48.0)],
34
+ sloc=[(0.0, 1.0), (0.2, 4.0), (0.35, 12.0), (1.0, 48.0)],
35
35
  ssystem=1,
36
36
  full_range=3.5,
37
37
  planes=0,
38
38
  ),
39
39
  planes=None,
40
40
  )
41
- bm3d = vsdenoise.BM3D.denoise(
42
- clip, sigma=luma_str, tr=1, ref=mv, profile=profile, planes=0
43
- )
44
- return vsdenoise.nl_means(bm3d, strength=chroma_str, tr=1, ref=mv, planes=[1, 2])
41
+ out = bm3d(clip, sigma=luma_str, tr=1, ref=mv, profile=profile, planes=0)
42
+ return vsdenoise.nl_means(out, h=chroma_str, tr=1, ref=mv, planes=[1, 2])
45
43
 
46
44
 
47
45
  def mc_dfttest(
@@ -62,7 +60,7 @@ def mc_dfttest(
62
60
  return mc_degrain(
63
61
  clip,
64
62
  prefilter=vsdenoise.Prefilter.DFTTEST,
65
- preset=vsdenoise.MVToolsPresets.HQ_SAD,
63
+ preset=vsdenoise.MVToolsPreset.HQ_SAD,
66
64
  thsad=thSAD,
67
65
  tr=2,
68
66
  refine=3 if blksize > 16 else 2,
@@ -201,12 +199,12 @@ def magic_denoise(clip: vs.VideoNode) -> vs.VideoNode:
201
199
  thscd1=300,
202
200
  )
203
201
 
204
- return DFTTest.denoise(
202
+ return DFTTest().denoise(
205
203
  clip,
206
204
  sloc=[(0.0, 0.8), (0.06, 1.1), (0.12, 1.0), (1.0, 1.0)],
207
205
  pmax=1000000,
208
206
  pmin=1.25,
209
- ftype=FilterType.MULT_RANGE,
207
+ ftype=DFTTest.FilterType.MULT_RANGE,
210
208
  tbsize=3,
211
209
  ssystem=1,
212
210
  )
@@ -0,0 +1,146 @@
1
+ from __future__ import annotations
2
+
3
+ import platform
4
+
5
+ import vstools
6
+ from vsmlrt import backendT
7
+ from vstools import vs
8
+
9
+ __all__ = ["rate_doubler", "decimation_fixer"]
10
+
11
+
12
+ def rate_doubler(
13
+ clip: vs.VideoNode, multi: int = 2, backend: backendT | None = None
14
+ ) -> vs.VideoNode:
15
+ """
16
+ A utility to scale the framerate of a video via frame interpolation.
17
+
18
+ Probably shouldn't just go spraying this everywhere,
19
+ it's more for fun and science than anything.
20
+ """
21
+ import vsmlrt
22
+
23
+ width = clip.width
24
+ height = clip.height
25
+ matrix = vstools.Matrix.from_video(clip)
26
+ transfer = vstools.Transfer.from_video(clip)
27
+ primaries = vstools.Primaries.from_video(clip)
28
+ clip = clip.misc.SCDetect()
29
+ clip = clip.resize.Bicubic(
30
+ format=vs.RGBS,
31
+ width=next_multiple_of(64, width),
32
+ height=next_multiple_of(64, height),
33
+ )
34
+ clip = vsmlrt.RIFE(
35
+ clip,
36
+ multi=multi,
37
+ model=vsmlrt.RIFEModel.v4_25_heavy,
38
+ # Why these defaults? Because running ML stuff on AMD on Windows sucks hard.
39
+ # Trial and error led me to finally find that ORT_DML works.
40
+ backend=(
41
+ backend
42
+ if backend
43
+ else (
44
+ vsmlrt.Backend.ORT_DML()
45
+ if platform.system() == "Windows"
46
+ else vsmlrt.Backend.TRT_RTX()
47
+ )
48
+ ),
49
+ )
50
+ # TODO: Handle other chroma samplings
51
+ clip = clip.resize.Bicubic(
52
+ format=vs.YUV420P16,
53
+ width=width,
54
+ height=height,
55
+ matrix=matrix,
56
+ transfer=transfer,
57
+ primaries=primaries,
58
+ )
59
+ return clip
60
+
61
+
62
+ def decimation_fixer(
63
+ clip: vs.VideoNode, cycle: int, offset: int = 0, backend: backendT | None = None
64
+ ) -> vs.VideoNode:
65
+ """
66
+ Attempts to interpolate frames that were removed by bad decimation.
67
+ Only works with static decimation cycles.
68
+ `cycle` should be the output cycle, i.e. what did the idiot who decimated this
69
+ pass into the decimation filter to achieve this monstrosity?
70
+
71
+ Yeah, I know, "ThiS is bAd AND yOu shoUldn'T Do IT".
72
+ Maybe people shouldn't decimate clips that don't need decimation.
73
+ Sometimes you can't "just get a better source".
74
+ """
75
+ import vsmlrt
76
+
77
+ if offset >= cycle - 1:
78
+ raise Exception("offset must be less than cycle - 1")
79
+ if cycle <= 0:
80
+ raise Exception("cycle must be greater than zero")
81
+
82
+ width = clip.width
83
+ height = clip.height
84
+ fps = clip.fps
85
+ input_cycle = cycle - 1
86
+ matrix = vstools.Matrix.from_video(clip)
87
+ transfer = vstools.Transfer.from_video(clip)
88
+ primaries = vstools.Primaries.from_video(clip)
89
+ clip = clip.misc.SCDetect()
90
+ clip = clip.resize.Bicubic(
91
+ format=vs.RGBS,
92
+ width=next_multiple_of(64, width),
93
+ height=next_multiple_of(64, height),
94
+ )
95
+ doubled = vsmlrt.RIFE(
96
+ clip,
97
+ model=vsmlrt.RIFEModel.v4_25_heavy,
98
+ backend=(
99
+ backend
100
+ if backend
101
+ else (
102
+ vsmlrt.Backend.ORT_DML()
103
+ if platform.system() == "Windows"
104
+ else vsmlrt.Backend.TRT_RTX()
105
+ )
106
+ ),
107
+ )
108
+
109
+ out_clip = None
110
+ # This is the frame after our insertion point
111
+ src_frame = offset
112
+ last_src_frame = 0
113
+ # This is the frame we want to grab from the doubled clip
114
+ doub_frame = offset * 2 - 1
115
+ while src_frame < clip.num_frames:
116
+ if src_frame > 0:
117
+ interp = doubled[doub_frame]
118
+ if out_clip is None:
119
+ out_clip = clip[last_src_frame:src_frame] + interp
120
+ else:
121
+ out_clip = out_clip + clip[last_src_frame:src_frame] + interp
122
+ last_src_frame = src_frame
123
+ src_frame += input_cycle
124
+ doub_frame += input_cycle * 2
125
+ out_clip += clip[last_src_frame:]
126
+ out_clip = out_clip.std.AssumeFPS(
127
+ fpsnum=fps.numerator * cycle // input_cycle, fpsden=fps.denominator
128
+ )
129
+
130
+ # TODO: Handle other chroma samplings
131
+ out_clip = out_clip.resize.Bicubic(
132
+ format=vs.YUV420P16,
133
+ width=width,
134
+ height=height,
135
+ matrix=matrix,
136
+ transfer=transfer,
137
+ primaries=primaries,
138
+ )
139
+ return out_clip
140
+
141
+
142
+ def next_multiple_of(multiple: int, param: int) -> int:
143
+ rem = param % multiple
144
+ if rem == 0:
145
+ return param
146
+ return param + (multiple - rem)
@@ -4,11 +4,11 @@ from dataclasses import dataclass
4
4
  from inspect import getfullargspec
5
5
  from typing import Any
6
6
 
7
- from vsaa.antialiasers.nnedi3 import Nnedi3SS
7
+ from vsaa.deinterlacers import NNEDI3
8
8
  from vskernels import (
9
9
  Hermite,
10
10
  Scaler,
11
- ScalerT,
11
+ ScalerLike,
12
12
  Spline36,
13
13
  )
14
14
  from vsscale import SSIM, ArtCNN, GenericScaler
@@ -58,11 +58,11 @@ def good_resize(
58
58
  if gpu:
59
59
  luma_scaler = ArtCNN()
60
60
  else:
61
- luma_scaler = Nnedi3SS(scaler=Hermite(sigmoid=True))
61
+ luma_scaler = NNEDI3(scaler=Hermite(sigmoid=True))
62
62
  else:
63
63
  luma_scaler = Hermite(sigmoid=True)
64
64
  elif is_upscale:
65
- luma_scaler = Nnedi3SS(scaler=SSIM())
65
+ luma_scaler = NNEDI3(scaler=SSIM())
66
66
  else:
67
67
  luma_scaler = SSIM()
68
68
 
@@ -73,8 +73,8 @@ def good_resize(
73
73
 
74
74
  @dataclass
75
75
  class HybridScaler(GenericScaler):
76
- luma_scaler: ScalerT
77
- chroma_scaler: ScalerT
76
+ luma_scaler: ScalerLike
77
+ chroma_scaler: ScalerLike
78
78
 
79
79
  def __post_init__(self) -> None:
80
80
  super().__post_init__()
@@ -82,7 +82,7 @@ class HybridScaler(GenericScaler):
82
82
  self._luma = Scaler.ensure_obj(self.luma_scaler)
83
83
  self._chroma = Scaler.ensure_obj(self.chroma_scaler)
84
84
 
85
- @inject_self.cached.property
85
+ @Scaler.cached_property
86
86
  def kernel_radius(self) -> int:
87
87
  return self._luma.kernel_radius
88
88
 
@@ -106,7 +106,7 @@ class HybridScaler(GenericScaler):
106
106
  return join(luma, chroma)
107
107
 
108
108
 
109
- def _get_scaler(scaler: ScalerT, **kwargs: Any) -> Scaler:
109
+ def _get_scaler(scaler: ScalerLike, **kwargs: Any) -> Scaler:
110
110
  scaler_cls = Scaler.from_param(scaler, _get_scaler)
111
111
 
112
112
  args = getfullargspec(scaler_cls).args
File without changes
File without changes
File without changes