Guest User

Untitled

a guest
Apr 26th, 2025
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.59 KB | None | 0 0
  1. import vapoursynth as vs
  2. import numpy as np
  3. from typing import Optional
  4.  
  5. core = vs.core
  6.  
  7.  
  8. def vapoursynth_to_numpy(frame: vs.VideoFrame) -> np.ndarray:
  9. """Optimized conversion from Vapoursynth frame to numpy array."""
  10. return np.dstack([np.array(frame[i], copy=False) for i in range(frame.format.num_planes)])
  11.  
  12. def numpy_to_vapoursynth(array: np.ndarray, reference_frame: vs.VideoFrame) -> vs.VideoFrame:
  13. """Optimized conversion from numpy array to Vapoursynth frame."""
  14. if array.ndim == 2:
  15. array = array[..., np.newaxis]
  16.  
  17. new_frame = reference_frame.copy()
  18.  
  19. for i in range(new_frame.format.num_planes):
  20. plane = array[..., i]
  21. if not plane.flags['C_CONTIGUOUS']:
  22. plane = np.ascontiguousarray(plane)
  23.  
  24. dest = np.array(new_frame[i], copy=False)
  25. np.copyto(dest, plane)
  26.  
  27. return new_frame
  28.  
  29. def test_numpy_conversion(clip: vs.VideoNode, strict: bool = True) -> vs.VideoNode:
  30. """Test the numpy conversion roundtrip."""
  31. def _test(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
  32. try:
  33. arr = vapoursynth_to_numpy(f)
  34. new_frame = numpy_to_vapoursynth(arr, f)
  35.  
  36. for i in range(f.format.num_planes):
  37. if not np.array_equal(np.array(f[i]), np.array(new_frame[i])):
  38. msg = f"Frame {n} plane {i} mismatch!"
  39. if strict:
  40. raise ValueError(msg)
  41. print("Warning:", msg)
  42. return f.text.Text("Conversion Error").get_frame(0)
  43.  
  44. return new_frame
  45. except Exception as e:
  46. if strict:
  47. raise
  48. print(f"Error processing frame {n}: {str(e)}")
  49. return f.text.Text("Error").get_frame(0)
  50.  
  51. return clip.std.ModifyFrame(clip, _test)
  52.  
  53. def AutoFixLineBorders(clip: vs.VideoNode, threshold: int = 24, bordersize: int = 4, debug: bool = False) -> vs.VideoNode:
  54. if clip.format.id != vs.YUV444P8:
  55. raise ValueError("AutoFixLineBorders: Only YUV444P8 input supported.")
  56.  
  57. def process_frame(n, clip, threshold, bordersize, debug):
  58. # Get the frame explicitly
  59. f = clip.get_frame(n)
  60. arr = vapoursynth_to_numpy(f)
  61. if arr.ndim == 2:
  62. arr = arr[..., np.newaxis]
  63.  
  64. y = arr[..., 0]
  65. u = arr[..., 1]
  66. v = arr[..., 2]
  67. height, width = y.shape
  68.  
  69. # Vectorized implementation
  70. first_non_dark = np.argmax(y > threshold, axis=1)
  71. first_non_dark[y.max(axis=1) <= threshold] = 0
  72. shifts = np.clip(first_non_dark - bordersize, 0, width)
  73.  
  74. if debug:
  75. new_y = np.where(shifts[:, None] > 0, 128, y)
  76. new_u = np.where(shifts[:, None] > 0, 255, u)
  77. new_v = np.where(shifts[:, None] > 0, 128, v)
  78. else:
  79. new_y = np.full_like(y, 16)
  80. new_u = np.full_like(u, 128)
  81. new_v = np.full_like(v, 128)
  82. for row in range(height):
  83. shift = shifts[row]
  84. if shift > 0:
  85. new_y[row, :-shift] = y[row, shift:]
  86. new_u[row, :-shift] = u[row, shift:]
  87. new_v[row, :-shift] = v[row, shift:]
  88.  
  89. result = np.dstack((new_y, new_u, new_v)).astype(np.uint8)
  90. return numpy_to_vapoursynth(result, f)
  91.  
  92. # Using std.ModifyFrame with the correct signature
  93. return clip.std.ModifyFrame(
  94. clips=[clip],
  95. selector=lambda n, f: process_frame(n, clip, threshold, bordersize, debug))
Advertisement
Add Comment
Please, Sign In to add comment