Spaces:
No application file
No application file
Create Main
Browse files
Main
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import gradio as gr
|
| 3 |
+
import torch
|
| 4 |
+
import trimesh
|
| 5 |
+
from PIL import Image
|
| 6 |
+
from rembg import remove
|
| 7 |
+
from tsr.system import TSR
|
| 8 |
+
from tsr.utils import remove_background, resize_foreground
|
| 9 |
+
|
| 10 |
+
# Check for hardware acceleration on the server host
|
| 11 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 12 |
+
|
| 13 |
+
print(f"Loading Generative 3D Transformer Model on: {device.upper()}...")
|
| 14 |
+
# Initialize the model weights globally once when the web server starts up
|
| 15 |
+
model = TSR.from_pretrained(
|
| 16 |
+
"stabilityai/TripoSR",
|
| 17 |
+
config_name="config.yaml",
|
| 18 |
+
weight_name="model.ckpt"
|
| 19 |
+
)
|
| 20 |
+
model.to(device)
|
| 21 |
+
model.eval()
|
| 22 |
+
|
| 23 |
+
def process_image_to_stl(input_image):
|
| 24 |
+
if input_image is None:
|
| 25 |
+
return None, "Error: No image uploaded."
|
| 26 |
+
|
| 27 |
+
try:
|
| 28 |
+
# Step 1: Strip image backgrounds natively on the server
|
| 29 |
+
print("Executing background removal layers...")
|
| 30 |
+
no_bg_image = remove(input_image)
|
| 31 |
+
|
| 32 |
+
# Step 2: Clear artifacts and scale to the neural network's bounding box
|
| 33 |
+
processed_img = remove_background(no_bg_image, "white")
|
| 34 |
+
processed_img = resize_foreground(processed_img, 0.85)
|
| 35 |
+
|
| 36 |
+
# Step 3: Run the Large Reconstruction Model to infer 3D spatial values
|
| 37 |
+
print("Processing 3D tensor field reconstruction...")
|
| 38 |
+
with torch.no_grad():
|
| 39 |
+
scene_codes = model([processed_img], device=device)
|
| 40 |
+
# Use Marching Cubes algorithm at a standard 256^3 resolution grid
|
| 41 |
+
meshes = model.extract_mesh(scene_codes, resolution=256)
|
| 42 |
+
ai_mesh = meshes
|
| 43 |
+
|
| 44 |
+
# Step 4: Extract the vertex mathematical arrays
|
| 45 |
+
vertices = ai_mesh.vertices.cpu().numpy()
|
| 46 |
+
faces = ai_mesh.faces.cpu().numpy()
|
| 47 |
+
|
| 48 |
+
# Step 5: Convert vertex points from local coordinates to a true 3D printable bed layout
|
| 49 |
+
vertices[:, [1, 2]] = vertices[:, [2, 1]] # Swap Y and Z axes
|
| 50 |
+
vertices[:, 1] *= -1 # Correct face-up inversion
|
| 51 |
+
|
| 52 |
+
# Create a solid geometry object
|
| 53 |
+
mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
|
| 54 |
+
mesh.process(validate=True) # Remove overlapping nodes
|
| 55 |
+
|
| 56 |
+
# Snap the absolute bottom boundary of the 3D mesh flat to Z=0 coordinate
|
| 57 |
+
z_min = mesh.bounds[0][2]
|
| 58 |
+
mesh.apply_translation([0, 0, -z_min])
|
| 59 |
+
|
| 60 |
+
# Step 6: Write out a local binary file on the server partition
|
| 61 |
+
output_filename = "generated_model.stl"
|
| 62 |
+
mesh.export(output_filename, file_type='stl')
|
| 63 |
+
|
| 64 |
+
status_msg = f"Success! Polygon Count: {len(mesh.faces)} | Solid Manifold: {mesh.is_watertight}"
|
| 65 |
+
return output_filename, status_msg
|
| 66 |
+
|
| 67 |
+
except Exception as e:
|
| 68 |
+
return None, f"An algorithmic pipeline error occurred: {str(e)}"
|
| 69 |
+
|
| 70 |
+
# Define the HTML/CSS user portal via Gradio framework
|
| 71 |
+
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
| 72 |
+
gr.Markdown("# Local-Engine AI Image-to-STL Converter")
|
| 73 |
+
gr.Markdown("Upload any image (objects, shapes, drawings) to synthesize a watertight, 3D-printable solid model without external API subscriptions.")
|
| 74 |
+
|
| 75 |
+
with gr.Row():
|
| 76 |
+
with gr.Column(scale=1):
|
| 77 |
+
input_img_slot = gr.Image(type="pil", label="Step 1: Upload Source Image")
|
| 78 |
+
submit_btn = gr.Button("Generate 3D STL Mesh", variant="primary")
|
| 79 |
+
|
| 80 |
+
with gr.Column(scale=1):
|
| 81 |
+
output_file_slot = gr.File(label="Step 2: Download Ready-to-Print STL File")
|
| 82 |
+
execution_log = gr.Textbox(label="System Pipeline Output Logs", interactive=False)
|
| 83 |
+
|
| 84 |
+
# Bind elements to backend trigger functions
|
| 85 |
+
submit_btn.click(
|
| 86 |
+
fn=process_image_to_stl,
|
| 87 |
+
inputs=[input_img_slot],
|
| 88 |
+
outputs=[output_file_slot, execution_log]
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
# Fire up the local webserver link on port 7860
|
| 92 |
+
if __name__ == "__main__":
|
| 93 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|