Spaces:
Running
on
Zero
Running
on
Zero
added texturing and fixed timestamp
Browse files- app.py +36 -18
- history.md +8 -0
app.py
CHANGED
@@ -9,6 +9,7 @@ import os
|
|
9 |
import trimesh
|
10 |
import time
|
11 |
from datetime import datetime
|
|
|
12 |
|
13 |
# Import potentially CUDA-initializing modules after 'spaces'
|
14 |
import torch
|
@@ -78,20 +79,21 @@ def generate_3d_model(depth, image_path, focallength_px, simplification_factor=0
|
|
78 |
try:
|
79 |
print("Starting 3D model generation")
|
80 |
# Load the RGB image and convert to a NumPy array
|
81 |
-
image =
|
|
|
82 |
|
83 |
# Ensure depth is a NumPy array
|
84 |
if isinstance(depth, torch.Tensor):
|
85 |
depth = depth.cpu().numpy()
|
86 |
|
87 |
# Resize depth to match image dimensions if necessary
|
88 |
-
if depth.shape !=
|
89 |
-
depth = cv2.resize(depth, (
|
90 |
|
91 |
height, width = depth.shape
|
92 |
|
93 |
print(f"3D model generation - Depth shape: {depth.shape}")
|
94 |
-
print(f"3D model generation - Image shape: {
|
95 |
|
96 |
# Compute camera intrinsic parameters
|
97 |
fx = fy = float(focallength_px) # Ensure focallength_px is a float
|
@@ -111,7 +113,7 @@ def generate_3d_model(depth, image_path, focallength_px, simplification_factor=0
|
|
111 |
vertices = np.vstack((X, Y, Z)).T
|
112 |
|
113 |
# Normalize RGB colors to [0, 1] for vertex coloring
|
114 |
-
colors =
|
115 |
|
116 |
print("Generating faces")
|
117 |
# Generate faces by connecting adjacent vertices to form triangles
|
@@ -161,12 +163,18 @@ def generate_3d_model(depth, image_path, focallength_px, simplification_factor=0
|
|
161 |
timestamp = int(time.time())
|
162 |
view_model_path = f'view_model_{timestamp}.obj'
|
163 |
download_model_path = f'download_model_{timestamp}.obj'
|
|
|
164 |
print("Exporting to view")
|
165 |
-
mesh.export(view_model_path)
|
166 |
print("Exporting to download")
|
167 |
-
mesh.export(download_model_path)
|
|
|
|
|
|
|
|
|
|
|
168 |
print("Export completed")
|
169 |
-
return view_model_path, download_model_path
|
170 |
except Exception as e:
|
171 |
print(f"Error in generate_3d_model: {str(e)}")
|
172 |
raise
|
@@ -201,12 +209,12 @@ def regenerate_3d_model(depth_csv, image_path, focallength_px, simplification_fa
|
|
201 |
depth = np.loadtxt(depth_csv, delimiter=',')
|
202 |
|
203 |
# Generate new 3D model with updated parameters
|
204 |
-
view_model_path, download_model_path = generate_3d_model(
|
205 |
depth, image_path, focallength_px,
|
206 |
simplification_factor, smoothing_iterations, thin_threshold
|
207 |
)
|
208 |
print("regenerated!")
|
209 |
-
return view_model_path, download_model_path
|
210 |
|
211 |
@spaces.GPU(duration=30)
|
212 |
def predict_depth(input_image):
|
@@ -267,24 +275,33 @@ def create_3d_model(depth_csv, image_path, focallength_px, simplification_factor
|
|
267 |
|
268 |
print(f"Loading image from: {image_path}")
|
269 |
|
270 |
-
view_model_path, download_model_path = generate_3d_model(
|
271 |
depth, image_path, focallength_px,
|
272 |
simplification_factor, smoothing_iterations, thin_threshold
|
273 |
)
|
274 |
print("3D model generated!")
|
275 |
-
return view_model_path, download_model_path, "3D model created successfully!"
|
276 |
except Exception as e:
|
277 |
error_message = f"An error occurred during 3D model creation: {str(e)}"
|
278 |
print(error_message)
|
279 |
-
return None, None, error_message
|
280 |
|
281 |
def get_last_commit_timestamp():
|
282 |
try:
|
|
|
283 |
timestamp = subprocess.check_output(['git', 'log', '-1', '--format=%cd', '--date=iso']).decode('utf-8').strip()
|
284 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
285 |
except Exception as e:
|
286 |
-
print(f"{str(e)}")
|
287 |
-
return
|
288 |
|
289 |
# Create the Gradio interface with appropriate input and output components.
|
290 |
last_updated = get_last_commit_timestamp()
|
@@ -314,6 +331,7 @@ with gr.Blocks() as iface:
|
|
314 |
with gr.Row():
|
315 |
view_3d_model = gr.Model3D(label="View 3D Model")
|
316 |
download_3d_model = gr.File(label="Download 3D Model (OBJ)")
|
|
|
317 |
|
318 |
with gr.Row():
|
319 |
simplification_factor = gr.Slider(minimum=0.1, maximum=1.0, value=0.8, step=0.1, label="Simplification Factor")
|
@@ -335,13 +353,13 @@ with gr.Blocks() as iface:
|
|
335 |
generate_3d_button.click(
|
336 |
create_3d_model,
|
337 |
inputs=[raw_depth_csv, input_image, hidden_focal_length, simplification_factor, smoothing_iterations, thin_threshold],
|
338 |
-
outputs=[view_3d_model, download_3d_model, model_status]
|
339 |
)
|
340 |
|
341 |
regenerate_button.click(
|
342 |
create_3d_model,
|
343 |
inputs=[raw_depth_csv, input_image, hidden_focal_length, simplification_factor, smoothing_iterations, thin_threshold],
|
344 |
-
outputs=[view_3d_model, download_3d_model, model_status]
|
345 |
)
|
346 |
|
347 |
# Launch the Gradio interface with sharing enabled
|
|
|
9 |
import trimesh
|
10 |
import time
|
11 |
from datetime import datetime
|
12 |
+
import pytz
|
13 |
|
14 |
# Import potentially CUDA-initializing modules after 'spaces'
|
15 |
import torch
|
|
|
79 |
try:
|
80 |
print("Starting 3D model generation")
|
81 |
# Load the RGB image and convert to a NumPy array
|
82 |
+
image = Image.open(image_path)
|
83 |
+
image_array = np.array(image)
|
84 |
|
85 |
# Ensure depth is a NumPy array
|
86 |
if isinstance(depth, torch.Tensor):
|
87 |
depth = depth.cpu().numpy()
|
88 |
|
89 |
# Resize depth to match image dimensions if necessary
|
90 |
+
if depth.shape != image_array.shape[:2]:
|
91 |
+
depth = cv2.resize(depth, (image_array.shape[1], image_array.shape[0]), interpolation=cv2.INTER_LINEAR)
|
92 |
|
93 |
height, width = depth.shape
|
94 |
|
95 |
print(f"3D model generation - Depth shape: {depth.shape}")
|
96 |
+
print(f"3D model generation - Image shape: {image_array.shape}")
|
97 |
|
98 |
# Compute camera intrinsic parameters
|
99 |
fx = fy = float(focallength_px) # Ensure focallength_px is a float
|
|
|
113 |
vertices = np.vstack((X, Y, Z)).T
|
114 |
|
115 |
# Normalize RGB colors to [0, 1] for vertex coloring
|
116 |
+
colors = image_array.reshape(-1, 3) / 255.0
|
117 |
|
118 |
print("Generating faces")
|
119 |
# Generate faces by connecting adjacent vertices to form triangles
|
|
|
163 |
timestamp = int(time.time())
|
164 |
view_model_path = f'view_model_{timestamp}.obj'
|
165 |
download_model_path = f'download_model_{timestamp}.obj'
|
166 |
+
|
167 |
print("Exporting to view")
|
168 |
+
mesh.export(view_model_path, include_texture=True)
|
169 |
print("Exporting to download")
|
170 |
+
mesh.export(download_model_path, include_texture=True)
|
171 |
+
|
172 |
+
# Save the texture image
|
173 |
+
texture_path = f'texture_{timestamp}.png'
|
174 |
+
image.save(texture_path)
|
175 |
+
|
176 |
print("Export completed")
|
177 |
+
return view_model_path, download_model_path, texture_path
|
178 |
except Exception as e:
|
179 |
print(f"Error in generate_3d_model: {str(e)}")
|
180 |
raise
|
|
|
209 |
depth = np.loadtxt(depth_csv, delimiter=',')
|
210 |
|
211 |
# Generate new 3D model with updated parameters
|
212 |
+
view_model_path, download_model_path, texture_path = generate_3d_model(
|
213 |
depth, image_path, focallength_px,
|
214 |
simplification_factor, smoothing_iterations, thin_threshold
|
215 |
)
|
216 |
print("regenerated!")
|
217 |
+
return view_model_path, download_model_path, texture_path
|
218 |
|
219 |
@spaces.GPU(duration=30)
|
220 |
def predict_depth(input_image):
|
|
|
275 |
|
276 |
print(f"Loading image from: {image_path}")
|
277 |
|
278 |
+
view_model_path, download_model_path, texture_path = generate_3d_model(
|
279 |
depth, image_path, focallength_px,
|
280 |
simplification_factor, smoothing_iterations, thin_threshold
|
281 |
)
|
282 |
print("3D model generated!")
|
283 |
+
return view_model_path, download_model_path, texture_path, "3D model created successfully!"
|
284 |
except Exception as e:
|
285 |
error_message = f"An error occurred during 3D model creation: {str(e)}"
|
286 |
print(error_message)
|
287 |
+
return None, None, None, error_message
|
288 |
|
289 |
def get_last_commit_timestamp():
|
290 |
try:
|
291 |
+
# Get the timestamp in a format that includes timezone information
|
292 |
timestamp = subprocess.check_output(['git', 'log', '-1', '--format=%cd', '--date=iso']).decode('utf-8').strip()
|
293 |
+
|
294 |
+
# Parse the timestamp, including the timezone
|
295 |
+
dt = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S %z")
|
296 |
+
|
297 |
+
# Convert to UTC
|
298 |
+
dt_utc = dt.astimezone(pytz.UTC)
|
299 |
+
|
300 |
+
# Format the date as desired
|
301 |
+
return dt_utc.strftime("%Y-%m-%d %H:%M:%S UTC")
|
302 |
except Exception as e:
|
303 |
+
print(f"Error getting last commit timestamp: {str(e)}")
|
304 |
+
return "Unknown"
|
305 |
|
306 |
# Create the Gradio interface with appropriate input and output components.
|
307 |
last_updated = get_last_commit_timestamp()
|
|
|
331 |
with gr.Row():
|
332 |
view_3d_model = gr.Model3D(label="View 3D Model")
|
333 |
download_3d_model = gr.File(label="Download 3D Model (OBJ)")
|
334 |
+
download_texture = gr.File(label="Download Texture (PNG)")
|
335 |
|
336 |
with gr.Row():
|
337 |
simplification_factor = gr.Slider(minimum=0.1, maximum=1.0, value=0.8, step=0.1, label="Simplification Factor")
|
|
|
353 |
generate_3d_button.click(
|
354 |
create_3d_model,
|
355 |
inputs=[raw_depth_csv, input_image, hidden_focal_length, simplification_factor, smoothing_iterations, thin_threshold],
|
356 |
+
outputs=[view_3d_model, download_3d_model, download_texture, model_status]
|
357 |
)
|
358 |
|
359 |
regenerate_button.click(
|
360 |
create_3d_model,
|
361 |
inputs=[raw_depth_csv, input_image, hidden_focal_length, simplification_factor, smoothing_iterations, thin_threshold],
|
362 |
+
outputs=[view_3d_model, download_3d_model, download_texture, model_status]
|
363 |
)
|
364 |
|
365 |
# Launch the Gradio interface with sharing enabled
|
history.md
CHANGED
@@ -22,6 +22,14 @@
|
|
22 |
4. Added a print statement just before returning from the `predict_depth` function to log all return values.
|
23 |
- These changes aim to prevent CUDA initialization in the main process and provide more detailed logging for troubleshooting.
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
## 2024-10-05 22:30 PST
|
26 |
### 3D Model Colorization and Thin Threshold Adjustment
|
27 |
- Problem 1: The generated 3D model lacks proper colorization from the original image.
|
|
|
22 |
4. Added a print statement just before returning from the `predict_depth` function to log all return values.
|
23 |
- These changes aim to prevent CUDA initialization in the main process and provide more detailed logging for troubleshooting.
|
24 |
|
25 |
+
## 2024-10-05 23:00 PST
|
26 |
+
### Persistent 3D Model Colorization Issue
|
27 |
+
- Problem: Despite previous attempts, the 3D model still appears colorless (gray) without the original image overlay.
|
28 |
+
- Next steps:
|
29 |
+
1. Review the texture mapping process in the 3D model generation.
|
30 |
+
2. Investigate alternative methods to apply color information to the 3D model.
|
31 |
+
3. Ensure color data is being properly passed and applied throughout the pipeline.
|
32 |
+
|
33 |
## 2024-10-05 22:30 PST
|
34 |
### 3D Model Colorization and Thin Threshold Adjustment
|
35 |
- Problem 1: The generated 3D model lacks proper colorization from the original image.
|