Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -17,6 +17,8 @@ import trimesh
|
|
17 |
from transformers import pipeline
|
18 |
from scipy.ndimage import gaussian_filter
|
19 |
import open3d as o3d
|
|
|
|
|
20 |
|
21 |
# Force CPU usage
|
22 |
os.environ["CUDA_VISIBLE_DEVICES"] = ""
|
@@ -96,13 +98,28 @@ def process_with_timeout(function, args, timeout):
|
|
96 |
def allowed_file(filename):
|
97 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
98 |
|
99 |
-
# Image preprocessing
|
100 |
def preprocess_image(image_path):
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
def load_model():
|
108 |
global depth_pipeline, model_loaded, model_loading
|
@@ -182,20 +199,20 @@ def depth_to_point_cloud(depth_map, image, detail_level):
|
|
182 |
h, w = depth_array.shape
|
183 |
x, y = np.meshgrid(np.arange(w), np.arange(h))
|
184 |
|
185 |
-
#
|
186 |
fx = fy = w * 0.5
|
187 |
cx, cy = w / 2, h / 2
|
188 |
|
189 |
-
# Convert to 3D coordinates
|
190 |
z = depth_array
|
191 |
x = (x - cx) * z / fx
|
192 |
-
y = (y - cy) * z / fy
|
193 |
|
194 |
points = np.stack([x, y, z], axis=-1).reshape(-1, 3)
|
195 |
colors = img_array.reshape(-1, 3) / 255.0
|
196 |
|
197 |
-
# Filter out invalid points (
|
198 |
-
mask = (z.reshape(-1) > 0.
|
199 |
points = points[mask]
|
200 |
colors = colors[mask]
|
201 |
|
@@ -223,6 +240,9 @@ def depth_to_point_cloud(depth_map, image, detail_level):
|
|
223 |
vertex_colors=vertex_colors
|
224 |
)
|
225 |
|
|
|
|
|
|
|
226 |
return trimesh_mesh
|
227 |
|
228 |
@app.route('/health', methods=['GET'])
|
@@ -297,7 +317,8 @@ def convert_image_to_3d():
|
|
297 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], f"{job_id}_{filename}")
|
298 |
file.save(filepath)
|
299 |
|
300 |
-
processing_jobs[job_id]
|
|
|
301 |
'status': 'processing',
|
302 |
'progress': 0,
|
303 |
'result_url': None,
|
@@ -484,7 +505,7 @@ def index():
|
|
484 |
"output_format": "glb",
|
485 |
"detail_level": "low, medium, or high - controls point cloud density"
|
486 |
},
|
487 |
-
"description": "This API creates 3D models from 2D images using Depth-Anything depth estimation. Images should have transparent backgrounds."
|
488 |
}), 200
|
489 |
|
490 |
if __name__ == '__main__':
|
|
|
17 |
from transformers import pipeline
|
18 |
from scipy.ndimage import gaussian_filter
|
19 |
import open3d as o3d
|
20 |
+
from rembg import remove
|
21 |
+
import cv2
|
22 |
|
23 |
# Force CPU usage
|
24 |
os.environ["CUDA_VISIBLE_DEVICES"] = ""
|
|
|
98 |
def allowed_file(filename):
|
99 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
100 |
|
101 |
+
# Image preprocessing: Remove background and resize
|
102 |
def preprocess_image(image_path):
|
103 |
+
try:
|
104 |
+
# Load image
|
105 |
+
with Image.open(image_path) as img:
|
106 |
+
# Remove background using rembg
|
107 |
+
img_no_bg = remove(img)
|
108 |
+
# Convert to RGB if it has an alpha channel
|
109 |
+
if img_no_bg.mode == 'RGBA':
|
110 |
+
img_no_bg = img_no_bg.convert('RGB')
|
111 |
+
# Resize to 512x512
|
112 |
+
img_no_bg = img_no_bg.resize((512, 512), Image.LANCZOS)
|
113 |
+
|
114 |
+
# Optional: Use cv2 for additional segmentation (e.g., refine mask)
|
115 |
+
img_array = np.array(img_no_bg)
|
116 |
+
gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
|
117 |
+
_, mask = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
|
118 |
+
img_array = cv2.bitwise_and(img_array, img_array, mask=mask)
|
119 |
+
|
120 |
+
return Image.fromarray(img_array)
|
121 |
+
except Exception as e:
|
122 |
+
raise Exception(f"Error preprocessing image: {str(e)}")
|
123 |
|
124 |
def load_model():
|
125 |
global depth_pipeline, model_loaded, model_loading
|
|
|
199 |
h, w = depth_array.shape
|
200 |
x, y = np.meshgrid(np.arange(w), np.arange(h))
|
201 |
|
202 |
+
# Camera intrinsics (assumed focal length)
|
203 |
fx = fy = w * 0.5
|
204 |
cx, cy = w / 2, h / 2
|
205 |
|
206 |
+
# Convert to 3D coordinates (Z-up for Unity)
|
207 |
z = depth_array
|
208 |
x = (x - cx) * z / fx
|
209 |
+
y = -(y - cy) * z / fy # Flip y-axis to correct orientation
|
210 |
|
211 |
points = np.stack([x, y, z], axis=-1).reshape(-1, 3)
|
212 |
colors = img_array.reshape(-1, 3) / 255.0
|
213 |
|
214 |
+
# Filter out invalid points (tighter range for foreground)
|
215 |
+
mask = (z.reshape(-1) > 0.2) & (z.reshape(-1) < 0.8)
|
216 |
points = points[mask]
|
217 |
colors = colors[mask]
|
218 |
|
|
|
240 |
vertex_colors=vertex_colors
|
241 |
)
|
242 |
|
243 |
+
# Rotate mesh to correct orientation (180 degrees around X-axis)
|
244 |
+
trimesh_mesh.apply_transform(trimesh.transformations.rotation_matrix(np.pi, [1, 0, 0]))
|
245 |
+
|
246 |
return trimesh_mesh
|
247 |
|
248 |
@app.route('/health', methods=['GET'])
|
|
|
317 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], f"{job_id}_{filename}")
|
318 |
file.save(filepath)
|
319 |
|
320 |
+
processing_jobs[job_id] =*.
|
321 |
+
{
|
322 |
'status': 'processing',
|
323 |
'progress': 0,
|
324 |
'result_url': None,
|
|
|
505 |
"output_format": "glb",
|
506 |
"detail_level": "low, medium, or high - controls point cloud density"
|
507 |
},
|
508 |
+
"description": "This API creates 3D models from 2D images using Depth-Anything depth estimation. Images should have transparent backgrounds for best results."
|
509 |
}), 200
|
510 |
|
511 |
if __name__ == '__main__':
|