HARSHIT-hash-07 commited on
Commit
805922c
·
1 Parent(s): 8e81ebe

fix(renderer): use exact plot_videos.py scaling pipeline (* 3 * 240 + offset)

Browse files
Files changed (1) hide show
  1. backend/video_renderer.py +31 -43
backend/video_renderer.py CHANGED
@@ -34,61 +34,49 @@ def draw_frame_2D(frame, joints):
34
 
35
  def render_skeleton_to_video(skeletons, output_path: str, fps: int = 25, mode: str = "standard"):
36
  """
37
- Renders a list of 3D skeletons to an mp4 video with Auto-Scaling.
38
- skeletons: A list/array of shape (frames, 50, 3)
39
- """
40
 
 
 
 
 
 
 
 
 
 
41
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
42
  out = cv2.VideoWriter(output_path, fourcc, fps, (650, 650), True)
43
 
44
- # Convert to numpy for easier manipulation
45
- skeletons_np = np.array(skeletons) # (F, 50, 3)
46
-
47
- # 1. AUTO-SCALING LOGIC
48
- # Find the bounding box across all frames to keep scaling consistent
49
- all_joints_2d = skeletons_np[:, :, :2] # (F, 50, 2)
50
- min_coords = np.min(all_joints_2d, axis=(0, 1))
51
- max_coords = np.max(all_joints_2d, axis=(0, 1))
52
- center = (min_coords + max_coords) / 2
53
-
54
- # Calculate scale factor to fit 80% of the 650x650 canvas
55
- range_coords = max_coords - min_coords
56
- max_range = np.max(range_coords)
57
- if max_range < 1e-6: max_range = 1.0 # Avoid div by zero
58
- scale = (650 * 0.7) / max_range
59
 
60
- for i, skel in enumerate(skeletons):
61
- frame = np.ones((650, 650, 3), np.uint8) * 245 # Slightly off-white
62
-
63
- # 2. Apply Auto-Scale and Center
64
- joints_2d = (np.array(skel)[:, :2] - center) * scale
65
- joints_2d = joints_2d + np.array([325, 325]) # Move to center of canvas
66
-
67
- # Draw the frame (we pass the pre-scaled joints)
68
- draw_frame_2D_v2(frame, joints_2d)
69
-
70
- label = "Generated Sign: SignBridge HQ" if mode == "hq" else "Generated Sign: Live AI Bridge"
71
- cv2.putText(frame, label, (130, 620), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (80, 80, 80), 2)
72
  out.write(frame)
73
 
74
  out.release()
75
-
76
- # Convert to web-compatible h264 using FFmpeg
77
  tmp_path = output_path.replace(".mp4", "_tmp.mp4")
78
  if os.path.exists(output_path):
79
  os.rename(output_path, tmp_path)
80
  os.system(f"ffmpeg -y -i {tmp_path} -vcodec libx264 -pix_fmt yuv420p -preset fast -crf 22 {output_path} -loglevel quiet")
81
  if os.path.exists(tmp_path):
82
  os.remove(tmp_path)
83
-
84
- return output_path
85
 
86
- def draw_frame_2D_v2(frame, joints_scaled):
87
- """Specific version that takes ALREADY scaled joints to avoid double scaling."""
88
- from SignIDD_CodeFiles.helpers import getSkeletalModelStructure
89
- skeleton = np.array(getSkeletalModelStructure())
90
-
91
- for j in range(skeleton.shape[0]):
92
- joint1 = joints_scaled[skeleton[j, 0]]
93
- joint2 = joints_scaled[skeleton[j, 1]]
94
- draw_line(frame, joint1, joint2, c=(40, 40, 40), t=1, width=2)
 
34
 
35
  def render_skeleton_to_video(skeletons, output_path: str, fps: int = 25, mode: str = "standard"):
36
  """
37
+ Renders skeleton frames to an MP4, using the SAME scaling as the original
38
+ plot_videos.py: joints * 3 * 240 + offset [350, 250].
 
39
 
40
+ skeletons: list of shape (frames, 50, 3)
41
+ """
42
+ import sys as _sys
43
+ _parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
44
+ if _parent not in _sys.path:
45
+ _sys.path.insert(0, _parent)
46
+ from SignIDD_CodeFiles.helpers import getSkeletalModelStructure
47
+
48
+ skeleton = np.array(getSkeletalModelStructure())
49
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
50
  out = cv2.VideoWriter(output_path, fourcc, fps, (650, 650), True)
51
 
52
+ for skel in skeletons:
53
+ frame = np.ones((650, 650, 3), np.uint8) * 255
54
+
55
+ # Exact same pipeline as plot_videos.py draw_frame_2D:
56
+ # joints * 3 (undo the /3 normalization from data prep)
57
+ # then * 240 (= 10 * 12 * 2, the display scale)
58
+ # then + [350, 250] (center offset)
59
+ joints_2d = np.array(skel)[:, :2] * 3 # (50, 2)
60
+ joints_scaled = joints_2d * 240
61
+ joints_offset = joints_scaled + np.array([350, 250])
62
+
63
+ for j in range(skeleton.shape[0]):
64
+ j1 = joints_offset[skeleton[j, 0]]
65
+ j2 = joints_offset[skeleton[j, 1]]
66
+ draw_line(frame, j1, j2, c=(0, 0, 0), t=1, width=2)
67
 
68
+ label = "SignBridge HQ" if mode == "hq" else "Live AI Bridge"
69
+ cv2.putText(frame, label, (230, 630), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (80, 80, 80), 2)
 
 
 
 
 
 
 
 
 
 
70
  out.write(frame)
71
 
72
  out.release()
73
+
74
+ # Convert to web-compatible H.264
75
  tmp_path = output_path.replace(".mp4", "_tmp.mp4")
76
  if os.path.exists(output_path):
77
  os.rename(output_path, tmp_path)
78
  os.system(f"ffmpeg -y -i {tmp_path} -vcodec libx264 -pix_fmt yuv420p -preset fast -crf 22 {output_path} -loglevel quiet")
79
  if os.path.exists(tmp_path):
80
  os.remove(tmp_path)
 
 
81
 
82
+ return output_path