OttoYu commited on
Commit
f664a16
·
verified ·
1 Parent(s): 08db879

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -12
app.py CHANGED
@@ -12,7 +12,7 @@ NUM_WORKERS = min(cpu_count(), 4)
12
  SHARED_MEMORY_NAME = 'shared_canvas'
13
 
14
  # === Parameters ===
15
- IMAGE_HEIGHT = 4096 * 2 # Default image height
16
  POINT_SIZE = 3
17
  SCALE_COLORS = False
18
  FULL_RES = False
@@ -20,16 +20,20 @@ MAX_RADIUS = 30
20
 
21
 
22
  def create_shared_memory_array(data, name, dtype):
 
23
  shm = shared_memory.SharedMemory(create=True, size=data.nbytes, name=name)
24
  shared_array = np.ndarray(data.shape, dtype=dtype, buffer=shm.buf)
25
  shared_array[:] = data
 
26
  return shm
27
 
28
 
29
  def release_shared_memory(name):
 
30
  shm = shared_memory.SharedMemory(name=name)
31
  shm.close()
32
  shm.unlink()
 
33
 
34
 
35
  def draw_points(start, length, canvas_shape, theta, phi, radius, color):
@@ -49,48 +53,58 @@ def draw_points(start, length, canvas_shape, theta, phi, radius, color):
49
 
50
 
51
  def project_point_cloud(input_file):
 
52
  try:
53
  point_cloud = laspy.read(input_file.name)
54
  except Exception as e:
55
  return f"Failed to read LAS file: {e}"
56
 
 
 
57
  height, width = IMAGE_HEIGHT, IMAGE_HEIGHT * 2
58
  output_shape = (height, width, 3)
59
-
60
  total_points = point_cloud.header.point_count
61
- print(f"[INFO] Loaded {total_points} points.")
62
 
 
 
63
  canvas = np.zeros(output_shape, dtype=np.uint16)
64
 
65
- # === Coordinate setup ===
 
66
  xyz = np.vstack((point_cloud.x, point_cloud.y, point_cloud.z)).T
67
  distances = np.linalg.norm(xyz, axis=1)
68
  distances[distances == 0] = 1e-6 # Avoid divide by zero
69
 
70
- # === Normalize distances for radius scaling ===
 
71
  dist_norm = (distances - distances.min()) / (distances.max() - distances.min())
72
 
73
- # === Compute angles ===
 
74
  theta = ((np.arctan2(point_cloud.y, point_cloud.x) + pi) / (2 * pi)) * width * FACTOR
75
  theta = np.mod(theta, width * FACTOR).astype(np.uint64)
76
 
77
  z_norm = np.clip(point_cloud.z / distances, -1.0, 1.0)
78
  phi = ((np.arccos(z_norm) / pi) * height * FACTOR).astype(np.uint64)
79
 
80
- # === Radius based on depth (closer larger radius) ===
 
81
  radii = (FACTOR * POINT_SIZE * (1 - dist_norm) + 1).astype(np.uint64)
82
  radii = np.clip(radii, 1, MAX_RADIUS)
83
 
84
- # === Colors ===
 
85
  colors = np.stack([point_cloud.blue, point_cloud.green, point_cloud.red], axis=-1).astype(np.uint16)
86
  if SCALE_COLORS:
87
  colors *= 256
88
  colors = np.clip(colors, 0, 65535)
89
 
90
- # === Shared Memory Canvas ===
91
  shm = create_shared_memory_array(canvas, SHARED_MEMORY_NAME, np.uint16)
92
 
93
- # === Start workers ===
 
94
  processes = []
95
  for i in range(NUM_WORKERS):
96
  start = int(i * total_points / NUM_WORKERS)
@@ -101,19 +115,27 @@ def project_point_cloud(input_file):
101
  p.start()
102
  processes.append(p)
103
 
 
104
  for p in processes:
105
  p.join()
 
106
 
107
- # === Finalize output ===
 
108
  final_image = np.ndarray(output_shape, dtype=np.uint16, buffer=shm.buf)
109
  if not FULL_RES:
 
110
  final_image = (final_image / 256).astype(np.uint8)
111
 
 
112
  output_file = "output_image.jpg"
 
113
  cv2.imwrite(output_file, final_image)
 
 
114
  release_shared_memory(SHARED_MEMORY_NAME)
115
- print(f"[INFO] Saved output to {output_file}")
116
 
 
117
  return output_file
118
 
119
 
 
12
  SHARED_MEMORY_NAME = 'shared_canvas'
13
 
14
  # === Parameters ===
15
+ IMAGE_HEIGHT = 4096 # Default image height
16
  POINT_SIZE = 3
17
  SCALE_COLORS = False
18
  FULL_RES = False
 
20
 
21
 
22
  def create_shared_memory_array(data, name, dtype):
23
+ print("[STEP 7] Creating shared memory...")
24
  shm = shared_memory.SharedMemory(create=True, size=data.nbytes, name=name)
25
  shared_array = np.ndarray(data.shape, dtype=dtype, buffer=shm.buf)
26
  shared_array[:] = data
27
+ print("[STEP 7] Shared memory initialized.")
28
  return shm
29
 
30
 
31
  def release_shared_memory(name):
32
+ print("[STEP 12] Releasing shared memory...")
33
  shm = shared_memory.SharedMemory(name=name)
34
  shm.close()
35
  shm.unlink()
36
+ print("[STEP 12] Shared memory released.")
37
 
38
 
39
  def draw_points(start, length, canvas_shape, theta, phi, radius, color):
 
53
 
54
 
55
  def project_point_cloud(input_file):
56
+ print("[STEP 1] Reading LAS file...")
57
  try:
58
  point_cloud = laspy.read(input_file.name)
59
  except Exception as e:
60
  return f"Failed to read LAS file: {e}"
61
 
62
+ print("[STEP 1] LAS file loaded successfully.")
63
+
64
  height, width = IMAGE_HEIGHT, IMAGE_HEIGHT * 2
65
  output_shape = (height, width, 3)
 
66
  total_points = point_cloud.header.point_count
67
+ print(f"[STEP 2] Point cloud shape: {total_points} points")
68
 
69
+ # === Step 3: Create blank canvas ===
70
+ print("[STEP 3] Initializing blank canvas...")
71
  canvas = np.zeros(output_shape, dtype=np.uint16)
72
 
73
+ # === Step 4: Compute distances ===
74
+ print("[STEP 4] Computing 3D distances...")
75
  xyz = np.vstack((point_cloud.x, point_cloud.y, point_cloud.z)).T
76
  distances = np.linalg.norm(xyz, axis=1)
77
  distances[distances == 0] = 1e-6 # Avoid divide by zero
78
 
79
+ # === Step 5: Normalize distances for depth-aware radius ===
80
+ print("[STEP 5] Normalizing distances...")
81
  dist_norm = (distances - distances.min()) / (distances.max() - distances.min())
82
 
83
+ # === Step 6: Compute angles ===
84
+ print("[STEP 6] Calculating spherical projection angles...")
85
  theta = ((np.arctan2(point_cloud.y, point_cloud.x) + pi) / (2 * pi)) * width * FACTOR
86
  theta = np.mod(theta, width * FACTOR).astype(np.uint64)
87
 
88
  z_norm = np.clip(point_cloud.z / distances, -1.0, 1.0)
89
  phi = ((np.arccos(z_norm) / pi) * height * FACTOR).astype(np.uint64)
90
 
91
+ # === Step 6.5: Compute radius based on distance ===
92
+ print("[STEP 6.5] Calculating radii for depth effect...")
93
  radii = (FACTOR * POINT_SIZE * (1 - dist_norm) + 1).astype(np.uint64)
94
  radii = np.clip(radii, 1, MAX_RADIUS)
95
 
96
+ # === Step 6.6: Compute colors ===
97
+ print("[STEP 6.6] Extracting and adjusting point colors...")
98
  colors = np.stack([point_cloud.blue, point_cloud.green, point_cloud.red], axis=-1).astype(np.uint16)
99
  if SCALE_COLORS:
100
  colors *= 256
101
  colors = np.clip(colors, 0, 65535)
102
 
103
+ # === Step 7: Create shared memory canvas ===
104
  shm = create_shared_memory_array(canvas, SHARED_MEMORY_NAME, np.uint16)
105
 
106
+ # === Step 8: Start multiprocessing drawing ===
107
+ print("[STEP 8] Launching drawing processes...")
108
  processes = []
109
  for i in range(NUM_WORKERS):
110
  start = int(i * total_points / NUM_WORKERS)
 
115
  p.start()
116
  processes.append(p)
117
 
118
+ print("[STEP 9] Waiting for drawing to complete...")
119
  for p in processes:
120
  p.join()
121
+ print("[STEP 9] All drawing processes finished.")
122
 
123
+ # === Step 10: Convert canvas back ===
124
+ print("[STEP 10] Retrieving final image from shared memory...")
125
  final_image = np.ndarray(output_shape, dtype=np.uint16, buffer=shm.buf)
126
  if not FULL_RES:
127
+ print("[STEP 10.1] Downsampling image to 8-bit for display...")
128
  final_image = (final_image / 256).astype(np.uint8)
129
 
130
+ # === Step 11: Save image ===
131
  output_file = "output_image.jpg"
132
+ print(f"[STEP 11] Saving image to: {output_file}")
133
  cv2.imwrite(output_file, final_image)
134
+
135
+ # === Step 12: Cleanup shared memory ===
136
  release_shared_memory(SHARED_MEMORY_NAME)
 
137
 
138
+ print("[STEP 13] Projection pipeline complete.")
139
  return output_file
140
 
141