jiten6555 commited on
Commit
cf37aee
·
verified ·
1 Parent(s): ef357b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -42
app.py CHANGED
@@ -1,51 +1,73 @@
1
  import torch
2
  import gradio as gr
3
- from PIL import Image
4
  import numpy as np
5
  import open3d as o3d
 
6
  import cv2
7
 
8
- class RobustImageTo3DConverter:
9
  def __init__(self):
10
- # Use OpenCV for depth estimation
11
- self.use_midas = False
 
 
 
 
 
12
 
13
- def estimate_depth(self, image):
14
  """
15
- Estimate depth using OpenCV's stereo algorithms
16
  """
17
- # Convert PIL Image to OpenCV format
18
- img_array = np.array(image)
19
 
20
- # Convert to grayscale
21
- gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
 
22
 
23
- # Create simple depth estimation using edge detection and blurring
24
- edges = cv2.Canny(gray, 100, 200)
25
- depth_map = cv2.distanceTransform(255 - edges, cv2.DIST_L2, 5)
26
 
27
- # Normalize depth map
28
- depth_map = cv2.normalize(depth_map, None, 0, 255, cv2.NORM_MINMAX)
 
 
29
 
30
- return depth_map
 
 
 
 
 
 
 
 
31
 
32
  def create_point_cloud(self, image, depth_map):
33
  """
34
- Convert depth map to 3D point cloud with reduced resolution
35
  """
36
  img_array = np.array(image)
37
  height, width = img_array.shape[:2]
38
 
39
- # Downsample to reduce computational load
40
- step = 5 # Reduce resolution
41
  points = []
42
  colors = []
43
 
44
  for y in range(0, height, step):
45
  for x in range(0, width, step):
46
- z = depth_map[y, x] / 255.0 # Normalize depth
47
- points.append([x, y, z * 10]) # Scale depth
48
- colors.append(img_array[y, x] / 255.0) # Normalize colors
 
 
 
 
 
 
 
49
 
50
  pcd = o3d.geometry.PointCloud()
51
  pcd.points = o3d.utility.Vector3dVector(points)
@@ -55,42 +77,48 @@ class RobustImageTo3DConverter:
55
 
56
  def convert_to_mesh(self, point_cloud):
57
  """
58
- Simplified mesh reconstruction for CPU
59
  """
 
60
  point_cloud.estimate_normals()
61
  point_cloud.orient_normals_consistent_tangent_plane(100)
62
 
63
- # Use simpler mesh reconstruction with lower depth
64
  mesh, _ = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
65
- point_cloud, depth=6 # Reduced depth for faster processing
66
  )
67
 
68
- # Color the mesh
69
- mesh.paint_uniform_color([0.7, 0.7, 0.7])
70
 
71
  return mesh
72
 
73
  def process_image(self, input_image):
74
  """
75
- CPU-friendly full pipeline for 3D conversion
76
  """
77
- # Estimate depth
 
 
 
 
78
  depth_map = self.estimate_depth(input_image)
79
 
80
  # Create point cloud
81
- point_cloud = self.create_point_cloud(input_image, depth_map)
82
 
83
  # Convert to mesh
84
  mesh = self.convert_to_mesh(point_cloud)
85
 
86
  # Save mesh
87
- output_path = "/tmp/converted_3d_model.obj"
88
  o3d.io.write_triangle_mesh(output_path, mesh)
89
 
90
  return output_path
91
 
92
  def create_huggingface_space():
93
- converter = RobustImageTo3DConverter()
 
94
 
95
  def convert_image(input_image):
96
  try:
@@ -98,10 +126,6 @@ def create_huggingface_space():
98
  if not isinstance(input_image, Image.Image):
99
  input_image = Image.fromarray(input_image)
100
 
101
- # Resize image if too large
102
- max_size = (800, 800)
103
- input_image.thumbnail(max_size, Image.LANCZOS)
104
-
105
  # Process image
106
  output_model = converter.process_image(input_image)
107
  return output_model
@@ -112,12 +136,9 @@ def create_huggingface_space():
112
  iface = gr.Interface(
113
  fn=convert_image,
114
  inputs=gr.Image(type="pil", label="Input Image"),
115
- outputs=[
116
- gr.File(label="3D Model (OBJ)"),
117
- gr.Textbox(label="Conversion Status")
118
- ],
119
- title="Robust Image to 3D Model Converter",
120
- description="Convert images to 3D models using OpenCV depth estimation and point cloud reconstruction."
121
  )
122
 
123
  return iface
 
1
  import torch
2
  import gradio as gr
 
3
  import numpy as np
4
  import open3d as o3d
5
+ from PIL import Image
6
  import cv2
7
 
8
+ class CPUFriendlyAIDepthTo3DConverter:
9
  def __init__(self):
10
+ # Load MiDaS depth estimation model with explicit CPU configuration
11
+ self.model = torch.hub.load('intel-isl/MiDaS', 'MiDaS_small', force_reload=False)
12
+ self.model.to('cpu') # Ensure model runs on CPU
13
+ self.model.eval()
14
+
15
+ # Preprocessing transforms
16
+ self.transform = torch.hub.load('intel-isl/MiDaS', 'transforms').small_transform
17
 
18
+ def estimate_depth(self, input_image):
19
  """
20
+ CPU-optimized depth estimation
21
  """
22
+ # Convert PIL Image to numpy
23
+ img = np.array(input_image)
24
 
25
+ # Ensure image is in RGB
26
+ if img.shape[-1] == 4: # If RGBA, convert to RGB
27
+ img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
28
 
29
+ # Preprocess image
30
+ input_batch = self.transform(img).unsqueeze(0).to('cpu')
 
31
 
32
+ # Estimate depth with minimal memory usage
33
+ with torch.no_grad():
34
+ prediction = self.model(input_batch)
35
+ depth = prediction.squeeze().cpu().numpy()
36
 
37
+ # Free up memory
38
+ torch.cuda.empty_cache()
39
+
40
+ # Normalize depth
41
+ depth_normalized = cv2.normalize(depth, None, 0, 255,
42
+ norm_type=cv2.NORM_MINMAX,
43
+ dtype=cv2.CV_8U)
44
+
45
+ return depth_normalized
46
 
47
  def create_point_cloud(self, image, depth_map):
48
  """
49
+ Efficient point cloud creation
50
  """
51
  img_array = np.array(image)
52
  height, width = img_array.shape[:2]
53
 
54
+ # More aggressive downsampling for memory efficiency
55
+ step = 4
56
  points = []
57
  colors = []
58
 
59
  for y in range(0, height, step):
60
  for x in range(0, width, step):
61
+ # Use depth as Z coordinate
62
+ z = depth_map[y, x] / 255.0 * 5 # Scaled depth
63
+ points.append([x, y, z])
64
+
65
+ # Safely get color
66
+ try:
67
+ color = img_array[y, x] / 255.0
68
+ colors.append(color)
69
+ except IndexError:
70
+ colors.append([0.5, 0.5, 0.5]) # Default color if out of bounds
71
 
72
  pcd = o3d.geometry.PointCloud()
73
  pcd.points = o3d.utility.Vector3dVector(points)
 
77
 
78
  def convert_to_mesh(self, point_cloud):
79
  """
80
+ Memory-efficient mesh conversion
81
  """
82
+ # Estimate and orient normals
83
  point_cloud.estimate_normals()
84
  point_cloud.orient_normals_consistent_tangent_plane(100)
85
 
86
+ # Lower depth for less memory consumption
87
  mesh, _ = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
88
+ point_cloud, depth=7 # Reduced from previous version
89
  )
90
 
91
+ # Simplified color handling
92
+ mesh.vertex_colors = point_cloud.colors
93
 
94
  return mesh
95
 
96
  def process_image(self, input_image):
97
  """
98
+ CPU-friendly full pipeline
99
  """
100
+ # Resize image to reduce memory usage
101
+ max_size = (800, 800)
102
+ input_image.thumbnail(max_size, Image.LANCZOS)
103
+
104
+ # Estimate depth using AI model
105
  depth_map = self.estimate_depth(input_image)
106
 
107
  # Create point cloud
108
+ point_cloud = self.create_point_cloud(np.array(input_image), depth_map)
109
 
110
  # Convert to mesh
111
  mesh = self.convert_to_mesh(point_cloud)
112
 
113
  # Save mesh
114
+ output_path = "/tmp/cpu_optimized_3d_model.obj"
115
  o3d.io.write_triangle_mesh(output_path, mesh)
116
 
117
  return output_path
118
 
119
  def create_huggingface_space():
120
+ # Initialize converter
121
+ converter = CPUFriendlyAIDepthTo3DConverter()
122
 
123
  def convert_image(input_image):
124
  try:
 
126
  if not isinstance(input_image, Image.Image):
127
  input_image = Image.fromarray(input_image)
128
 
 
 
 
 
129
  # Process image
130
  output_model = converter.process_image(input_image)
131
  return output_model
 
136
  iface = gr.Interface(
137
  fn=convert_image,
138
  inputs=gr.Image(type="pil", label="Input Image"),
139
+ outputs=gr.File(label="3D Model (OBJ)"),
140
+ title="CPU-Friendly AI Image to 3D Converter",
141
+ description="Convert images to 3D models using lightweight AI depth estimation."
 
 
 
142
  )
143
 
144
  return iface