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.
|