mac9087 commited on
Commit
afec0dd
·
verified ·
1 Parent(s): bf928c6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +134 -39
app.py CHANGED
@@ -259,7 +259,7 @@ def enhance_depth_map(depth_map, detail_level='medium'):
259
 
260
  # Convert depth map to 3D mesh with significantly enhanced detail
261
  def depth_to_mesh(depth_map, image, resolution=100, detail_level='medium'):
262
- """Convert depth map to 3D mesh with highly improved detail preservation"""
263
  # First, enhance the depth map for better details
264
  enhanced_depth = enhance_depth_map(depth_map, detail_level)
265
 
@@ -314,7 +314,38 @@ def depth_to_mesh(depth_map, image, resolution=100, detail_level='medium'):
314
  # Create vertices
315
  vertices = np.vstack([x_grid.flatten(), -y_grid.flatten(), -z_values.flatten()]).T
316
 
317
- # Create faces (triangles) with optimized winding for better normals
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  faces = []
319
  for i in range(resolution-1):
320
  for j in range(resolution-1):
@@ -323,25 +354,31 @@ def depth_to_mesh(depth_map, image, resolution=100, detail_level='medium'):
323
  p3 = (i + 1) * resolution + j
324
  p4 = (i + 1) * resolution + (j + 1)
325
 
326
- # Calculate normals to ensure consistent orientation
327
- v1 = vertices[p1]
328
- v2 = vertices[p2]
329
- v3 = vertices[p3]
330
- v4 = vertices[p4]
331
-
332
- # Calculate normals for both possible triangulations
333
- # and choose the one that's more consistent
334
- norm1 = np.cross(v2-v1, v4-v1)
335
- norm2 = np.cross(v4-v3, v1-v3)
336
-
337
- if np.dot(norm1, norm2) >= 0:
338
- # Standard triangulation
339
- faces.append([p1, p2, p4])
340
- faces.append([p1, p4, p3])
341
- else:
342
- # Alternative triangulation for smoother surface
343
- faces.append([p1, p2, p3])
344
- faces.append([p2, p4, p3])
 
 
 
 
 
 
345
 
346
  faces = np.array(faces)
347
 
@@ -356,10 +393,11 @@ def depth_to_mesh(depth_map, image, resolution=100, detail_level='medium'):
356
  else:
357
  img_array = image
358
 
359
- # Create vertex colors with improved sampling
360
  if resolution <= img_array.shape[0] and resolution <= img_array.shape[1]:
361
  # Create vertex colors by sampling the image with bilinear interpolation
362
  vertex_colors = np.zeros((vertices.shape[0], 4), dtype=np.uint8)
 
363
 
364
  # Get normalized coordinates for sampling
365
  for i in range(resolution):
@@ -378,23 +416,26 @@ def depth_to_mesh(depth_map, image, resolution=100, detail_level='medium'):
378
 
379
  vertex_idx = i * resolution + j
380
 
381
- if len(img_array.shape) == 3 and img_array.shape[2] == 3: # RGB
382
- # Perform bilinear interpolation for each color channel
383
- r = int((1-wx)*(1-wy)*img_array[y0, x0, 0] + wx*(1-wy)*img_array[y0, x1, 0] +
384
- (1-wx)*wy*img_array[y1, x0, 0] + wx*wy*img_array[y1, x1, 0])
385
- g = int((1-wx)*(1-wy)*img_array[y0, x0, 1] + wx*(1-wy)*img_array[y0, x1, 1] +
386
- (1-wx)*wy*img_array[y1, x0, 1] + wx*wy*img_array[y1, x1, 1])
387
- b = int((1-wx)*(1-wy)*img_array[y0, x0, 2] + wx*(1-wy)*img_array[y0, x1, 2] +
388
- (1-wx)*wy*img_array[y1, x0, 2] + wx*wy*img_array[y1, x1, 2])
389
-
390
- vertex_colors[vertex_idx, :3] = [r, g, b]
391
- vertex_colors[vertex_idx, 3] = 255 # Alpha
392
- elif len(img_array.shape) == 3 and img_array.shape[2] == 4: # RGBA
393
- for c in range(4): # For each RGBA channel
394
- vertex_colors[vertex_idx, c] = int((1-wx)*(1-wy)*img_array[y0, x0, c] +
395
- wx*(1-wy)*img_array[y0, x1, c] +
396
- (1-wx)*wy*img_array[y1, x0, c] +
397
- wx*wy*img_array[y1, x1, c])
 
 
 
398
  else:
399
  # Handle grayscale with bilinear interpolation
400
  gray = int((1-wx)*(1-wy)*img_array[y0, x0] + wx*(1-wy)*img_array[y0, x1] +
@@ -415,6 +456,60 @@ def depth_to_mesh(depth_map, image, resolution=100, detail_level='medium'):
415
 
416
  return mesh
417
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
  @app.route('/health', methods=['GET'])
419
  def health_check():
420
  return jsonify({
 
259
 
260
  # Convert depth map to 3D mesh with significantly enhanced detail
261
  def depth_to_mesh(depth_map, image, resolution=100, detail_level='medium'):
262
+ """Convert depth map to 3D mesh with highly improved detail preservation and transparency support"""
263
  # First, enhance the depth map for better details
264
  enhanced_depth = enhance_depth_map(depth_map, detail_level)
265
 
 
314
  # Create vertices
315
  vertices = np.vstack([x_grid.flatten(), -y_grid.flatten(), -z_values.flatten()]).T
316
 
317
+ # Create transparency mask for the image if it has an alpha channel
318
+ # This will be used to filter out faces that contain transparent pixels
319
+ has_alpha = False
320
+ alpha_mask = np.ones((resolution, resolution), dtype=bool)
321
+
322
+ if image is not None:
323
+ if isinstance(image, Image.Image):
324
+ if image.mode == 'RGBA':
325
+ has_alpha = True
326
+ # Convert image to numpy array with alpha channel
327
+ img_array = np.array(image)
328
+ # Extract alpha channel
329
+ alpha_channel = img_array[:, :, 3]
330
+
331
+ # Create alpha mask by sampling alpha channel at grid positions
332
+ for i in range(resolution):
333
+ for j in range(resolution):
334
+ img_y = int(i * (img_array.shape[0] - 1) / (resolution - 1))
335
+ img_x = int(j * (img_array.shape[1] - 1) / (resolution - 1))
336
+ alpha_mask[i, j] = alpha_channel[img_y, img_x] > 10 # Threshold for transparency
337
+ elif isinstance(image, np.ndarray) and image.shape[2] == 4: # RGBA numpy array
338
+ has_alpha = True
339
+ alpha_channel = image[:, :, 3]
340
+
341
+ # Sample alpha channel at grid positions
342
+ for i in range(resolution):
343
+ for j in range(resolution):
344
+ img_y = int(i * (image.shape[0] - 1) / (resolution - 1))
345
+ img_x = int(j * (image.shape[1] - 1) / (resolution - 1))
346
+ alpha_mask[i, j] = alpha_channel[img_y, img_x] > 10 # Threshold for transparency
347
+
348
+ # Create faces (triangles) with transparency handling
349
  faces = []
350
  for i in range(resolution-1):
351
  for j in range(resolution-1):
 
354
  p3 = (i + 1) * resolution + j
355
  p4 = (i + 1) * resolution + (j + 1)
356
 
357
+ # Only create faces if all vertices are visible (non-transparent)
358
+ if not has_alpha or (alpha_mask[i, j] and alpha_mask[i, j+1] and
359
+ alpha_mask[i+1, j] and alpha_mask[i+1, j+1]):
360
+ # Calculate normals to ensure consistent orientation
361
+ v1 = vertices[p1]
362
+ v2 = vertices[p2]
363
+ v3 = vertices[p3]
364
+ v4 = vertices[p4]
365
+
366
+ # Calculate normals for both possible triangulations
367
+ # and choose the one that's more consistent
368
+ norm1 = np.cross(v2-v1, v4-v1)
369
+ norm2 = np.cross(v4-v3, v1-v3)
370
+
371
+ if np.dot(norm1, norm2) >= 0:
372
+ # Standard triangulation
373
+ faces.append([p1, p2, p4])
374
+ faces.append([p1, p4, p3])
375
+ else:
376
+ # Alternative triangulation for smoother surface
377
+ faces.append([p1, p2, p3])
378
+ faces.append([p2, p4, p3])
379
+
380
+ if len(faces) == 0:
381
+ raise ValueError("No faces generated - image may be completely transparent")
382
 
383
  faces = np.array(faces)
384
 
 
393
  else:
394
  img_array = image
395
 
396
+ # Create vertex colors with improved sampling and transparency support
397
  if resolution <= img_array.shape[0] and resolution <= img_array.shape[1]:
398
  # Create vertex colors by sampling the image with bilinear interpolation
399
  vertex_colors = np.zeros((vertices.shape[0], 4), dtype=np.uint8)
400
+ vertex_colors[:, 3] = 255 # Default alpha to opaque
401
 
402
  # Get normalized coordinates for sampling
403
  for i in range(resolution):
 
416
 
417
  vertex_idx = i * resolution + j
418
 
419
+ # Apply vertex colors based on image format
420
+ if len(img_array.shape) == 3:
421
+ if img_array.shape[2] == 4: # RGBA
422
+ # Set colors with alpha channel
423
+ for c in range(4): # For each RGBA channel
424
+ vertex_colors[vertex_idx, c] = int((1-wx)*(1-wy)*img_array[y0, x0, c] +
425
+ wx*(1-wy)*img_array[y0, x1, c] +
426
+ (1-wx)*wy*img_array[y1, x0, c] +
427
+ wx*wy*img_array[y1, x1, c])
428
+ elif img_array.shape[2] == 3: # RGB
429
+ # Apply bilinear interpolation for each color channel
430
+ r = int((1-wx)*(1-wy)*img_array[y0, x0, 0] + wx*(1-wy)*img_array[y0, x1, 0] +
431
+ (1-wx)*wy*img_array[y1, x0, 0] + wx*wy*img_array[y1, x1, 0])
432
+ g = int((1-wx)*(1-wy)*img_array[y0, x0, 1] + wx*(1-wy)*img_array[y0, x1, 1] +
433
+ (1-wx)*wy*img_array[y1, x0, 1] + wx*wy*img_array[y1, x1, 1])
434
+ b = int((1-wx)*(1-wy)*img_array[y0, x0, 2] + wx*(1-wy)*img_array[y0, x1, 2] +
435
+ (1-wx)*wy*img_array[y1, x0, 2] + wx*wy*img_array[y1, x1, 2])
436
+
437
+ vertex_colors[vertex_idx, :3] = [r, g, b]
438
+ vertex_colors[vertex_idx, 3] = 255 # Full opacity for RGB images
439
  else:
440
  # Handle grayscale with bilinear interpolation
441
  gray = int((1-wx)*(1-wy)*img_array[y0, x0] + wx*(1-wy)*img_array[y0, x1] +
 
456
 
457
  return mesh
458
 
459
+ # Enhanced image preprocessing to properly handle PNGs with transparency
460
+ def preprocess_image(image_path):
461
+ with Image.open(image_path) as img:
462
+ # Get original mode to check if it has transparency
463
+ original_mode = img.mode
464
+
465
+ # Convert to RGB or RGBA as needed
466
+ if original_mode == 'RGBA':
467
+ # Keep alpha channel for transparency
468
+ img = img.convert("RGBA")
469
+ else:
470
+ # Otherwise use RGB
471
+ img = img.convert("RGB")
472
+
473
+ # Resize if the image is too large
474
+ if img.width > MAX_DIMENSION or img.height > MAX_DIMENSION:
475
+ # Calculate new dimensions while preserving aspect ratio
476
+ if img.width > img.height:
477
+ new_width = MAX_DIMENSION
478
+ new_height = int(img.height * (MAX_DIMENSION / img.width))
479
+ else:
480
+ new_height = MAX_DIMENSION
481
+ new_width = int(img.width * (MAX_DIMENSION / img.height))
482
+
483
+ # Use high-quality Lanczos resampling for better detail preservation
484
+ img = img.resize((new_width, new_height), Image.LANCZOS)
485
+
486
+ # Handle enhancement only for RGB (non-transparent) parts
487
+ if original_mode != 'RGBA':
488
+ # Convert to numpy array for additional preprocessing
489
+ img_array = np.array(img)
490
+
491
+ # Optional: Apply adaptive histogram equalization for better contrast
492
+ # This helps the depth model detect more details
493
+ if len(img_array.shape) == 3 and img_array.shape[2] == 3:
494
+ # Convert to LAB color space
495
+ lab = cv2.cvtColor(img_array, cv2.COLOR_RGB2LAB)
496
+ l, a, b = cv2.split(lab)
497
+
498
+ # Apply CLAHE to L channel
499
+ clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
500
+ cl = clahe.apply(l)
501
+
502
+ # Merge channels back
503
+ enhanced_lab = cv2.merge((cl, a, b))
504
+
505
+ # Convert back to RGB
506
+ img_array = cv2.cvtColor(enhanced_lab, cv2.COLOR_LAB2RGB)
507
+
508
+ # Convert back to PIL Image
509
+ img = Image.fromarray(img_array)
510
+
511
+ return img
512
+
513
  @app.route('/health', methods=['GET'])
514
  def health_check():
515
  return jsonify({