Spaces:
mashroo
/
Runtime error

YoussefAnso commited on
Commit
44c19b3
·
1 Parent(s): 9bb78c9

Refactor texture baking in vertex_color_to_uv_textured_glb function to use vectorized operations. This change improves performance by precomputing face data and applying vectorized barycentric tests, enhancing the efficiency of texture generation.

Browse files
Files changed (1) hide show
  1. inference.py +48 -45
inference.py CHANGED
@@ -21,54 +21,57 @@ def vertex_color_to_uv_textured_glb(obj_path, glb_path, texture_size=512):
21
  vertex_colors = vertex_colors[vmapping]
22
  mesh.vertices = vertices
23
  mesh.faces = indices
24
- # Bake texture
25
  buffer_size = texture_size * 2
26
  texture_buffer = np.zeros((buffer_size, buffer_size, 4), dtype=np.uint8)
27
- def barycentric_interpolate(v0, v1, v2, c0, c1, c2, p):
28
- v0v1 = v1 - v0
29
- v0v2 = v2 - v0
30
- v0p = p - v0
31
- d00 = np.dot(v0v1, v0v1)
32
- d01 = np.dot(v0v1, v0v2)
33
- d11 = np.dot(v0v2, v0v2)
34
- d20 = np.dot(v0p, v0v1)
35
- d21 = np.dot(v0p, v0v2)
36
- denom = d00 * d11 - d01 * d01
37
- if abs(denom) < 1e-8:
38
- return (c0 + c1 + c2) / 3
39
- v = (d11 * d20 - d01 * d21) / denom
40
- w = (d00 * d21 - d01 * d20) / denom
41
- u = 1.0 - v - w
42
- u = np.clip(u, 0, 1)
43
- v = np.clip(v, 0, 1)
44
- w = np.clip(w, 0, 1)
45
- return u * c0 + v * c1 + w * c2
46
- def is_point_in_triangle(p, v0, v1, v2):
47
  def sign(p1, p2, p3):
48
- return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
49
- d1 = sign(p, v0, v1)
50
- d2 = sign(p, v1, v2)
51
- d3 = sign(p, v2, v0)
52
- has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
53
- has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
54
- return not (has_neg and has_pos)
55
- for face in mesh.faces:
56
- uv0, uv1, uv2 = uvs[face]
57
- c0, c1, c2 = vertex_colors[face]
58
- uv0 = (uv0 * (buffer_size - 1)).astype(int)
59
- uv1 = (uv1 * (buffer_size - 1)).astype(int)
60
- uv2 = (uv2 * (buffer_size - 1)).astype(int)
61
- min_x = max(int(np.floor(min(uv0[0], uv1[0], uv2[0]))), 0)
62
- max_x = min(int(np.ceil(max(uv0[0], uv1[0], uv2[0]))), buffer_size - 1)
63
- min_y = max(int(np.floor(min(uv0[1], uv1[1], uv2[1]))), 0)
64
- max_y = min(int(np.ceil(max(uv0[1], uv1[1], uv2[1]))), buffer_size - 1)
65
- for y in range(min_y, max_y + 1):
66
- for x in range(min_x, max_x + 1):
67
- p = np.array([x + 0.5, y + 0.5])
68
- if is_point_in_triangle(p, uv0, uv1, uv2):
69
- color = barycentric_interpolate(uv0, uv1, uv2, c0, c1, c2, p)
70
- texture_buffer[y, x, :3] = np.clip(color, 0, 255).astype(np.uint8)
71
- texture_buffer[y, x, 3] = 255
 
 
 
 
 
72
  # Inpainting, filtering, and downsampling
73
  image_bgra = texture_buffer.copy()
74
  mask = (image_bgra[:, :, 3] == 0).astype(np.uint8) * 255
 
21
  vertex_colors = vertex_colors[vmapping]
22
  mesh.vertices = vertices
23
  mesh.faces = indices
24
+ # Bake texture (vectorized)
25
  buffer_size = texture_size * 2
26
  texture_buffer = np.zeros((buffer_size, buffer_size, 4), dtype=np.uint8)
27
+ # Precompute face data
28
+ face_uvs = uvs[mesh.faces]
29
+ face_colors = vertex_colors[mesh.faces]
30
+ # Compute bounding boxes for all faces
31
+ min_xy = np.floor(np.min(face_uvs, axis=1) * (buffer_size - 1)).astype(int)
32
+ max_xy = np.ceil(np.max(face_uvs, axis=1) * (buffer_size - 1)).astype(int)
33
+ for i in range(len(mesh.faces)):
34
+ uv0, uv1, uv2 = face_uvs[i]
35
+ c0, c1, c2 = face_colors[i]
36
+ min_x, min_y = min_xy[i]
37
+ max_x, max_y = max_xy[i]
38
+ # Create a grid of pixel coordinates in the bounding box
39
+ xs = np.arange(min_x, max_x + 1)
40
+ ys = np.arange(min_y, max_y + 1)
41
+ xv, yv = np.meshgrid(xs, ys)
42
+ pts = np.stack([xv, yv], axis=-1).reshape(-1, 2) + 0.5
43
+ # Barycentric test (vectorized)
44
+ v0, v1, v2 = uv0 * (buffer_size - 1), uv1 * (buffer_size - 1), uv2 * (buffer_size - 1)
 
 
45
  def sign(p1, p2, p3):
46
+ return (p1[..., 0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[..., 1] - p3[1])
47
+ d1 = sign(pts, v0, v1)
48
+ d2 = sign(pts, v1, v2)
49
+ d3 = sign(pts, v2, v0)
50
+ mask = ~((d1 < 0) | (d2 < 0) | (d3 < 0)) & ~((d1 > 0) & (d2 > 0) & (d3 > 0))
51
+ inside_pts = pts[mask]
52
+ if len(inside_pts) == 0:
53
+ continue
54
+ # Barycentric coordinates (vectorized)
55
+ def barycentric(p, v0, v1, v2):
56
+ v0v1 = v1 - v0
57
+ v0v2 = v2 - v0
58
+ v0p = p - v0
59
+ d00 = np.dot(v0v1, v0v1)
60
+ d01 = np.dot(v0v1, v0v2)
61
+ d11 = np.dot(v0v2, v0v2)
62
+ d20 = np.dot(v0p, v0v1)
63
+ d21 = np.dot(v0p, v0v2)
64
+ denom = d00 * d11 - d01 * d01
65
+ v = (d11 * d20 - d01 * d21) / denom
66
+ w = (d00 * d21 - d01 * d20) / denom
67
+ u = 1.0 - v - w
68
+ return np.clip(u, 0, 1), np.clip(v, 0, 1), np.clip(w, 0, 1)
69
+ u, v, w = barycentric(inside_pts, v0, v1, v2)
70
+ colors = (u[:, None] * c0 + v[:, None] * c1 + w[:, None] * c2)
71
+ xi = inside_pts[:, 0].astype(int)
72
+ yi = inside_pts[:, 1].astype(int)
73
+ texture_buffer[yi, xi, :3] = np.clip(colors, 0, 255).astype(np.uint8)
74
+ texture_buffer[yi, xi, 3] = 255
75
  # Inpainting, filtering, and downsampling
76
  image_bgra = texture_buffer.copy()
77
  mask = (image_bgra[:, :, 3] == 0).astype(np.uint8) * 255