Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -476,17 +476,10 @@ def render_single_frame(
|
|
| 476 |
blank = np.ones((frame_height, frame_width, 3), dtype=np.uint8) * 200
|
| 477 |
return blank
|
| 478 |
|
| 479 |
-
#
|
| 480 |
-
#
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
# Compute center for camera positioning
|
| 485 |
-
mesh_center = verts_used.mean(axis=0)
|
| 486 |
-
if fixed_center is not None:
|
| 487 |
-
camera_target = fixed_center
|
| 488 |
-
else:
|
| 489 |
-
camera_target = mesh_center
|
| 490 |
|
| 491 |
# Create scene
|
| 492 |
scene = pyrender.Scene(bg_color=bg_color, ambient_light=[0.4, 0.4, 0.4])
|
|
@@ -499,10 +492,19 @@ def render_single_frame(
|
|
| 499 |
baseColorFactor=color
|
| 500 |
)
|
| 501 |
|
| 502 |
-
# Create mesh
|
| 503 |
-
mesh = trimesh.Trimesh(vertices=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
mesh_render = pyrender.Mesh.from_trimesh(mesh, material=material, smooth=True)
|
| 505 |
scene.add(mesh_render)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
|
| 507 |
# Camera setup
|
| 508 |
camera = pyrender.IntrinsicsCamera(
|
|
@@ -511,13 +513,22 @@ def render_single_frame(
|
|
| 511 |
znear=0.1, zfar=20.0
|
| 512 |
)
|
| 513 |
|
| 514 |
-
# Camera pose: positioned
|
| 515 |
-
#
|
|
|
|
|
|
|
| 516 |
camera_pose = np.eye(4)
|
| 517 |
camera_pose[0, 3] = camera_target[0] # Center X
|
| 518 |
-
camera_pose[1, 3] = camera_target[1] # Center Y
|
| 519 |
-
camera_pose[2, 3] = camera_target[2]
|
| 520 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
|
| 522 |
scene.add(camera, pose=camera_pose)
|
| 523 |
|
|
@@ -619,17 +630,16 @@ def render_video(
|
|
| 619 |
# Apply rotation to all frames
|
| 620 |
# (T, V, 3) dot (3, 3) -> (T, V, 3)
|
| 621 |
verts = np.matmul(verts, rot_matrix[:3, :3].T)
|
| 622 |
-
# Apply orientation fix: rotate 180 degrees around X-axis (like compare_vqvae.py)
|
| 623 |
-
verts = verts.copy()
|
| 624 |
-
verts[..., 1:] *= -1
|
| 625 |
-
|
| 626 |
# Trim last few frames to remove end-of-sequence artifacts
|
| 627 |
T_total = verts.shape[0]
|
| 628 |
trim_amount = min(8, int(T_total * 0.15))
|
| 629 |
T = max(5, T_total - trim_amount)
|
| 630 |
|
| 631 |
-
# Compute fixed camera target from first frame (
|
| 632 |
-
|
|
|
|
|
|
|
|
|
|
| 633 |
|
| 634 |
frames = []
|
| 635 |
for t in range(T):
|
|
@@ -668,12 +678,6 @@ def render_comparison_video(
|
|
| 668 |
if not ensure_pyrender():
|
| 669 |
raise RuntimeError("PyRender not available")
|
| 670 |
|
| 671 |
-
# Apply orientation fix: rotate 180 degrees around X-axis (like compare_vqvae.py)
|
| 672 |
-
verts1 = verts1.copy()
|
| 673 |
-
verts2 = verts2.copy()
|
| 674 |
-
verts1[..., 1:] *= -1
|
| 675 |
-
verts2[..., 1:] *= -1
|
| 676 |
-
|
| 677 |
# Match lengths and trim
|
| 678 |
T_total = min(verts1.shape[0], verts2.shape[0])
|
| 679 |
trim_amount = min(8, int(T_total * 0.15))
|
|
@@ -682,9 +686,13 @@ def render_comparison_video(
|
|
| 682 |
verts1 = verts1[:T]
|
| 683 |
verts2 = verts2[:T]
|
| 684 |
|
| 685 |
-
# Compute fixed camera targets
|
| 686 |
-
|
| 687 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 688 |
|
| 689 |
labels = [label1, label2]
|
| 690 |
|
|
|
|
| 476 |
blank = np.ones((frame_height, frame_width, 3), dtype=np.uint8) * 200
|
| 477 |
return blank
|
| 478 |
|
| 479 |
+
# IMPORTANT: Rotate mesh 180 degrees around X-axis (like visualize.py)
|
| 480 |
+
# This fixes the coordinate system so we view from the front
|
| 481 |
+
rot_matrix = trimesh.transformations.rotation_matrix(np.radians(180), [1, 0, 0])
|
| 482 |
+
verts_rotated = np.dot(verts, rot_matrix[:3, :3].T)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
|
| 484 |
# Create scene
|
| 485 |
scene = pyrender.Scene(bg_color=bg_color, ambient_light=[0.4, 0.4, 0.4])
|
|
|
|
| 492 |
baseColorFactor=color
|
| 493 |
)
|
| 494 |
|
| 495 |
+
# Create mesh with rotated vertices
|
| 496 |
+
mesh = trimesh.Trimesh(vertices=verts_rotated, faces=faces)
|
| 497 |
+
# Fix normals to ensure proper face rendering
|
| 498 |
+
# This is critical for proper face/lip visibility - ensures all faces point outward
|
| 499 |
+
mesh.fix_normals()
|
| 500 |
+
# Recompute vertex normals for smooth shading
|
| 501 |
+
mesh.vertex_normals
|
| 502 |
mesh_render = pyrender.Mesh.from_trimesh(mesh, material=material, smooth=True)
|
| 503 |
scene.add(mesh_render)
|
| 504 |
+
|
| 505 |
+
# Compute center for camera positioning (using rotated vertices)
|
| 506 |
+
mesh_center = verts_rotated.mean(axis=0)
|
| 507 |
+
camera_target = fixed_center if fixed_center is not None else mesh_center
|
| 508 |
|
| 509 |
# Camera setup
|
| 510 |
camera = pyrender.IntrinsicsCamera(
|
|
|
|
| 513 |
znear=0.1, zfar=20.0
|
| 514 |
)
|
| 515 |
|
| 516 |
+
# Camera pose: positioned in front of the subject, looking at them
|
| 517 |
+
# After 180-degree rotation, Z points down
|
| 518 |
+
# Camera should be at negative Z (in front) looking at positive Z
|
| 519 |
+
# This matches visualize.py exactly
|
| 520 |
camera_pose = np.eye(4)
|
| 521 |
camera_pose[0, 3] = camera_target[0] # Center X
|
| 522 |
+
camera_pose[1, 3] = camera_target[1] # Center Y (body center)
|
| 523 |
+
camera_pose[2, 3] = camera_target[2] - camera_distance # In front, distance controls zoom
|
| 524 |
+
|
| 525 |
+
# Camera orientation: flip to look at subject (SOKE-style)
|
| 526 |
+
# This rotation makes camera look toward +Z (at the subject)
|
| 527 |
+
camera_pose[:3, :3] = np.array([
|
| 528 |
+
[1, 0, 0],
|
| 529 |
+
[0, -1, 0],
|
| 530 |
+
[0, 0, -1]
|
| 531 |
+
])
|
| 532 |
|
| 533 |
scene.add(camera, pose=camera_pose)
|
| 534 |
|
|
|
|
| 630 |
# Apply rotation to all frames
|
| 631 |
# (T, V, 3) dot (3, 3) -> (T, V, 3)
|
| 632 |
verts = np.matmul(verts, rot_matrix[:3, :3].T)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 633 |
# Trim last few frames to remove end-of-sequence artifacts
|
| 634 |
T_total = verts.shape[0]
|
| 635 |
trim_amount = min(8, int(T_total * 0.15))
|
| 636 |
T = max(5, T_total - trim_amount)
|
| 637 |
|
| 638 |
+
# Compute fixed camera target from first frame (rotation happens inside render_single_frame)
|
| 639 |
+
# We need to compute it from rotated vertices for consistency
|
| 640 |
+
rot_matrix = trimesh.transformations.rotation_matrix(np.radians(180), [1, 0, 0])
|
| 641 |
+
verts_rotated_first = np.dot(verts[0], rot_matrix[:3, :3].T)
|
| 642 |
+
fixed_center = verts_rotated_first.mean(axis=0)
|
| 643 |
|
| 644 |
frames = []
|
| 645 |
for t in range(T):
|
|
|
|
| 678 |
if not ensure_pyrender():
|
| 679 |
raise RuntimeError("PyRender not available")
|
| 680 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 681 |
# Match lengths and trim
|
| 682 |
T_total = min(verts1.shape[0], verts2.shape[0])
|
| 683 |
trim_amount = min(8, int(T_total * 0.15))
|
|
|
|
| 686 |
verts1 = verts1[:T]
|
| 687 |
verts2 = verts2[:T]
|
| 688 |
|
| 689 |
+
# Compute fixed camera targets (rotation happens inside render_single_frame)
|
| 690 |
+
# We need to compute from rotated vertices for consistency
|
| 691 |
+
rot_matrix = trimesh.transformations.rotation_matrix(np.radians(180), [1, 0, 0])
|
| 692 |
+
verts1_rotated_first = np.dot(verts1[0], rot_matrix[:3, :3].T)
|
| 693 |
+
verts2_rotated_first = np.dot(verts2[0], rot_matrix[:3, :3].T)
|
| 694 |
+
fixed_center1 = verts1_rotated_first.mean(axis=0)
|
| 695 |
+
fixed_center2 = verts2_rotated_first.mean(axis=0)
|
| 696 |
|
| 697 |
labels = [label1, label2]
|
| 698 |
|