A19grey commited on
Commit
2b69b2a
1 Parent(s): 5784c10

Added 3D mesh cleanup to remove artifacts v1

Browse files
Files changed (1) hide show
  1. app.py +46 -8
app.py CHANGED
@@ -57,14 +57,6 @@ def resize_image(image_path, max_size=1024):
57
  def generate_3d_model(depth, image_path, focallength_px):
58
  """
59
  Generate a textured 3D mesh from the depth map and the original image.
60
-
61
- Args:
62
- depth (np.ndarray): 2D array representing depth in meters.
63
- image_path (str): Path to the RGB image.
64
- focallength_px (float): Focal length in pixels.
65
-
66
- Returns:
67
- tuple: Paths to the exported 3D model files for viewing and downloading.
68
  """
69
  # Load the RGB image and convert to a NumPy array
70
  image = np.array(Image.open(image_path))
@@ -116,6 +108,28 @@ def generate_3d_model(depth, image_path, focallength_px):
116
  # Create the mesh using Trimesh with vertex colors
117
  mesh = trimesh.Trimesh(vertices=vertices, faces=faces, vertex_colors=colors)
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  # Export the mesh to OBJ files with unique filenames
120
  timestamp = int(time.time())
121
  view_model_path = f'view_model_{timestamp}.obj'
@@ -124,6 +138,30 @@ def generate_3d_model(depth, image_path, focallength_px):
124
  mesh.export(download_model_path)
125
  return view_model_path, download_model_path
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  @spaces.GPU(duration=20)
128
  def predict_depth(input_image):
129
  temp_file = None
 
57
  def generate_3d_model(depth, image_path, focallength_px):
58
  """
59
  Generate a textured 3D mesh from the depth map and the original image.
 
 
 
 
 
 
 
 
60
  """
61
  # Load the RGB image and convert to a NumPy array
62
  image = np.array(Image.open(image_path))
 
108
  # Create the mesh using Trimesh with vertex colors
109
  mesh = trimesh.Trimesh(vertices=vertices, faces=faces, vertex_colors=colors)
110
 
111
+ # Mesh cleaning and improvement steps
112
+ print("Original mesh - vertices: {}, faces: {}".format(len(mesh.vertices), len(mesh.faces)))
113
+
114
+ # 1. Mesh simplification
115
+ mesh = mesh.simplify_quadratic_decimation(target_percent=0.8)
116
+ print("After simplification - vertices: {}, faces: {}".format(len(mesh.vertices), len(mesh.faces)))
117
+
118
+ # 2. Remove small disconnected components
119
+ components = mesh.split(only_watertight=False)
120
+ if len(components) > 1:
121
+ areas = np.array([c.area for c in components])
122
+ mesh = components[np.argmax(areas)]
123
+ print("After removing small components - vertices: {}, faces: {}".format(len(mesh.vertices), len(mesh.faces)))
124
+
125
+ # 3. Smooth the mesh
126
+ mesh = mesh.smoothed()
127
+ print("After smoothing - vertices: {}, faces: {}".format(len(mesh.vertices), len(mesh.faces)))
128
+
129
+ # 4. Remove thin features
130
+ mesh = remove_thin_features(mesh)
131
+ print("After removing thin features - vertices: {}, faces: {}".format(len(mesh.vertices), len(mesh.faces)))
132
+
133
  # Export the mesh to OBJ files with unique filenames
134
  timestamp = int(time.time())
135
  view_model_path = f'view_model_{timestamp}.obj'
 
138
  mesh.export(download_model_path)
139
  return view_model_path, download_model_path
140
 
141
+ def remove_thin_features(mesh, thickness_threshold=0.01):
142
+ """
143
+ Remove thin features from the mesh.
144
+ """
145
+ # Calculate edge lengths
146
+ edges = mesh.edges_unique
147
+ edge_points = mesh.vertices[edges]
148
+ edge_lengths = np.linalg.norm(edge_points[:, 0] - edge_points[:, 1], axis=1)
149
+
150
+ # Identify short edges
151
+ short_edges = edges[edge_lengths < thickness_threshold]
152
+
153
+ # Collapse short edges
154
+ for edge in short_edges:
155
+ try:
156
+ mesh.collapse_edge(edge)
157
+ except:
158
+ pass # Skip if edge collapse fails
159
+
160
+ # Remove any newly created degenerate faces
161
+ mesh.remove_degenerate_faces()
162
+
163
+ return mesh
164
+
165
  @spaces.GPU(duration=20)
166
  def predict_depth(input_image):
167
  temp_file = None