Guest User

Untitled

a guest
Apr 26th, 2025
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.79 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. """Convert a Vapoursynth frame to a numpy array."""
  10. planes = []
  11. for i in range(frame.format.num_planes):
  12. plane = np.array(frame[i], copy=False)
  13. planes.append(plane)
  14.  
  15. return np.dstack(planes) if len(planes) > 1 else planes[0]
  16.  
  17. def numpy_to_vapoursynth(array: np.ndarray, reference_frame: vs.VideoFrame) -> vs.VideoFrame:
  18. """Convert a numpy array to a Vapoursynth frame."""
  19. if array.ndim == 2:
  20. array = array[..., np.newaxis]
  21.  
  22. # Create a new writable frame
  23. new_frame = core.std.BlankClip(
  24. width=reference_frame.width,
  25. height=reference_frame.height,
  26. format=reference_frame.format.id,
  27. length=1
  28. ).get_frame(0)
  29.  
  30. # Ensure the frame is writable
  31. new_frame = new_frame.copy()
  32.  
  33. for i in range(new_frame.format.num_planes):
  34. plane_data = array[..., i]
  35. if not plane_data.flags['C_CONTIGUOUS']:
  36. plane_data = np.ascontiguousarray(plane_data)
  37.  
  38. # Get plane dimensions
  39. width = new_frame.width if i == 0 else new_frame.width >> new_frame.format.subsampling_w
  40. height = new_frame.height if i == 0 else new_frame.height >> new_frame.format.subsampling_h
  41.  
  42. # Reshape if necessary
  43. if plane_data.shape != (height, width):
  44. plane_data = plane_data.reshape((height, width))
  45.  
  46. # Create a new numpy array for the plane
  47. dest_plane = np.array(new_frame[i], copy=False)
  48. np.copyto(dest_plane, plane_data)
  49.  
  50. return new_frame
  51.  
  52.  
  53. def test_numpy_conversion(clip: vs.VideoNode, strict: bool = True) -> vs.VideoNode:
  54. """Test the numpy conversion roundtrip."""
  55. def _test(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
  56. try:
  57. arr = vapoursynth_to_numpy(f)
  58. new_frame = numpy_to_vapoursynth(arr, f)
  59.  
  60. for i in range(f.format.num_planes):
  61. if not np.array_equal(np.array(f[i]), np.array(new_frame[i])):
  62. msg = f"Frame {n} plane {i} mismatch!"
  63. if strict:
  64. raise ValueError(msg)
  65. print("Warning:", msg)
  66. return f.text.Text("Conversion Error").get_frame(0)
  67.  
  68. return new_frame
  69. except Exception as e:
  70. if strict:
  71. raise
  72. print(f"Error processing frame {n}: {str(e)}")
  73. return f.text.Text("Error").get_frame(0)
  74.  
  75. return clip.std.ModifyFrame(clip, _test)
  76.  
  77. def AutoFixLineBorders(clip: vs.VideoNode, threshold: int = 24, bordersize: int = 4, debug: bool = False) -> vs.VideoNode:
  78. if clip.format.id != vs.YUV444P8:
  79. raise ValueError("AutoFixLineBorders: Only YUV444P8 input supported.")
  80.  
  81. def shift_lines(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
  82. arr = vapoursynth_to_numpy(f)
  83. if arr.ndim == 2:
  84. arr = arr[..., np.newaxis]
  85.  
  86. y = arr[..., 0]
  87. u = arr[..., 1]
  88. v = arr[..., 2]
  89.  
  90. height, width = y.shape
  91.  
  92. new_y = np.copy(y)
  93. new_u = np.copy(u)
  94. new_v = np.copy(v)
  95.  
  96. for row in range(height):
  97. # Zähle die dunklen Pixel am Anfang der Zeile
  98. count = 0
  99. for col in range(width):
  100. if y[row, col] <= threshold:
  101. count += 1
  102. else:
  103. break
  104. detected_bordersize = count
  105.  
  106. if detected_bordersize > 60:
  107. detected_bordersize = 0
  108.  
  109. shift = detected_bordersize - bordersize
  110.  
  111. if shift == 0:
  112. continue # Keine Verschiebung nötig
  113.  
  114. if debug:
  115. # Nur debug Markierung
  116. new_y[row, :] = 128 # Grau
  117. new_u[row, :] = 255 # Lila/Orange
  118. new_v[row, :] = 128
  119. continue
  120.  
  121. if shift > 0:
  122. # Nach links verschieben, Rechts auffüllen mit Schwarz
  123. new_y[row, :-shift] = y[row, shift:]
  124. new_y[row, -shift:] = 16 # Y=16 (schwarz)
  125.  
  126. new_u[row, :-shift] = u[row, shift:]
  127. new_u[row, -shift:] = 128 # U=128 (neutral)
  128.  
  129. new_v[row, :-shift] = v[row, shift:]
  130. new_v[row, -shift:] = 128 # V=128 (neutral)
  131. # shift < 0 würde bedeuten "nach rechts" – das brauchst du NICHT!
  132.  
  133. result = np.dstack((new_y, new_u, new_v)).astype(np.uint8)
  134. return numpy_to_vapoursynth(result, f)
  135.  
  136. return clip.std.ModifyFrame(clips=clip, selector=shift_lines)
  137.  
Advertisement
Add Comment
Please, Sign In to add comment