LiangLabUMB commited on
Commit
904db41
·
verified ·
1 Parent(s): 5add708

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -348
app.py DELETED
@@ -1,348 +0,0 @@
1
- import gradio as gr
2
- import spaces
3
- from cellpose import models
4
- import numpy as np
5
- import cv2
6
- import matplotlib.pyplot as plt
7
- import tempfile
8
- from PIL import Image
9
- import io
10
- from huggingface_hub import hf_hub_download
11
-
12
- HF_REPO_ID = "myang4218/cellposemodel"
13
- MODEL_OPTIONS = {
14
- "Hemocytometer Model": "hemocytometermodel.npy",
15
- "General Model": "generalmodel.npy"
16
- }
17
-
18
- loaded_models = {}
19
-
20
- def debug_editor_data(editor_data):
21
- """Debug function to understand the structure of ImageEditor data"""
22
- if editor_data is None:
23
- return "No data provided"
24
-
25
- info = f"Type: {type(editor_data)}\n"
26
-
27
- if isinstance(editor_data, dict):
28
- info += f"Keys: {list(editor_data.keys())}\n"
29
- for key, value in editor_data.items():
30
- info += f" {key}: {type(value)}\n"
31
- if key == 'layers' and value:
32
- info += f" Layers count: {len(value)}\n"
33
- for i, layer in enumerate(value):
34
- info += f" Layer {i}: {type(layer)}\n"
35
- if hasattr(layer, 'size'):
36
- info += f" Size: {layer.size}\n"
37
- info += f" Mode: {layer.mode}\n"
38
- else:
39
- if hasattr(editor_data, 'size'):
40
- info += f"Size: {editor_data.size}\n"
41
- info += f"Mode: {editor_data.mode}\n"
42
-
43
- return info
44
-
45
- def extract_region_from_editor(editor_data):
46
- """Extract the selected region from ImageEditor data"""
47
- if editor_data is None:
48
- return None, None
49
-
50
- # ImageEditor can return different formats depending on version
51
- # Let's handle the most common cases
52
-
53
- if isinstance(editor_data, dict):
54
- # Case 1: Dictionary with 'background' and 'layers'
55
- background = editor_data.get('background')
56
- layers = editor_data.get('layers', [])
57
-
58
- if background is None:
59
- return None, None
60
-
61
- # Convert background to numpy array
62
- background_np = np.array(background)
63
-
64
- # If there are drawn layers, try to extract selection
65
- if layers and len(layers) > 0:
66
- # Get the first layer
67
- selection_layer = layers[0]
68
-
69
- # Convert to numpy array
70
- selection_np = np.array(selection_layer)
71
-
72
- # Find non-transparent/non-black pixels as selection
73
- if len(selection_np.shape) == 3:
74
- # For RGB, look for non-black pixels
75
- if selection_np.shape[2] == 4: # RGBA
76
- # Use alpha channel
77
- mask = selection_np[:, :, 3] > 0
78
- else: # RGB
79
- # Use non-black pixels
80
- mask = np.any(selection_np > 0, axis=2)
81
- else:
82
- # Grayscale
83
- mask = selection_np > 0
84
-
85
- # Find bounding box of the selection
86
- coords = np.where(mask)
87
- if len(coords[0]) > 0:
88
- y_min, y_max = coords[0].min(), coords[0].max()
89
- x_min, x_max = coords[1].min(), coords[1].max()
90
-
91
- # Add some padding to ensure we don't get tiny regions
92
- pad = 5
93
- h, w = background_np.shape[:2]
94
- y_min = max(0, y_min - pad)
95
- y_max = min(h, y_max + pad)
96
- x_min = max(0, x_min - pad)
97
- x_max = min(w, x_max + pad)
98
-
99
- # Extract the region
100
- region = background_np[y_min:y_max+1, x_min:x_max+1]
101
- return region, (x_min, y_min, x_max, y_max)
102
-
103
- # If no selection, return the full image
104
- return background_np, None
105
-
106
- else:
107
- # Case 2: Direct PIL Image
108
- if hasattr(editor_data, 'size'): # Check if it's a PIL Image
109
- image_np = np.array(editor_data)
110
- return image_np, None
111
- else:
112
- return None, None
113
-
114
- def crop_image_with_coords(image_np, coords):
115
- """Crop image using provided coordinates"""
116
- if coords is None:
117
- return image_np
118
-
119
- x_min, y_min, x_max, y_max = coords
120
- return image_np[y_min:y_max+1, x_min:x_max+1]
121
-
122
- @spaces.GPU
123
- def segment_and_count(editor_data, model_choice, crop_coords=None):
124
- """
125
- Segment and count cells in the selected region
126
-
127
- Args:
128
- editor_data: Data from ImageEditor component
129
- model_choice: Selected model for segmentation
130
- crop_coords: Optional manual crop coordinates as "x_min,y_min,x_max,y_max"
131
- """
132
- try:
133
- # Debug info
134
- debug_info = debug_editor_data(editor_data)
135
-
136
- # Load the model
137
- model_filename = MODEL_OPTIONS[model_choice]
138
- model_path = hf_hub_download(repo_id=HF_REPO_ID, filename=model_filename)
139
-
140
- if model_filename in loaded_models:
141
- model = loaded_models[model_filename]
142
- else:
143
- model = models.CellposeModel(gpu=True, pretrained_model=model_path)
144
- loaded_models[model_filename] = model
145
-
146
- # Extract region from editor
147
- region_np, region_coords = extract_region_from_editor(editor_data)
148
-
149
- if region_np is None:
150
- return 0, None, f"No image provided. Debug info:\n{debug_info}"
151
-
152
- # If manual crop coordinates are provided, use them instead
153
- if crop_coords and crop_coords.strip():
154
- try:
155
- coords = [int(x.strip()) for x in crop_coords.split(',')]
156
- if len(coords) == 4:
157
- x_min, y_min, x_max, y_max = coords
158
- # Ensure coordinates are within image bounds
159
- h, w = region_np.shape[:2]
160
- x_min = max(0, min(x_min, w-1))
161
- y_min = max(0, min(y_min, h-1))
162
- x_max = max(x_min+1, min(x_max, w))
163
- y_max = max(y_min+1, min(y_max, h))
164
-
165
- region_np = region_np[y_min:y_max, x_min:x_max]
166
- region_coords = (x_min, y_min, x_max, y_max)
167
- except ValueError:
168
- pass # Invalid coordinates, continue with current region
169
-
170
- # If grayscale, convert to RGB
171
- if len(region_np.shape) == 2:
172
- region_np = cv2.cvtColor(region_np, cv2.COLOR_GRAY2RGB)
173
- elif len(region_np.shape) == 3 and region_np.shape[2] == 4:
174
- # Handle RGBA images
175
- region_np = cv2.cvtColor(region_np, cv2.COLOR_RGBA2RGB)
176
-
177
- # Run Cellpose on the selected region
178
- masks, flows, styles = model.eval(region_np, diameter=None, channels=[0, 0])
179
-
180
- # Count unique cells
181
- cell_count = len(np.unique(masks)) - 1 # subtract 1 for background
182
-
183
- # Create better overlay visualization
184
- overlay = region_np.copy().astype(np.float32)
185
-
186
- # Create colored mask overlay
187
- if masks.max() > 0:
188
- # Generate random colors for each cell
189
- np.random.seed(42) # For reproducible colors
190
- colors = np.random.randint(0, 255, size=(masks.max() + 1, 3))
191
- colors[0] = [0, 0, 0] # Background stays black
192
-
193
- # Create colored overlay
194
- colored_mask = colors[masks]
195
-
196
- # Blend with original image
197
- alpha = 0.4
198
- overlay = (1 - alpha) * overlay + alpha * colored_mask
199
-
200
- # Ensure values are in valid range and convert to uint8
201
- overlay = np.clip(overlay, 0, 255).astype(np.uint8)
202
-
203
- # Convert result to PIL Image for output
204
- overlay_image = Image.fromarray(overlay)
205
-
206
- # Create info message
207
- if region_coords:
208
- info_msg = f"Processed region: {region_coords[0]},{region_coords[1]} to {region_coords[2]},{region_coords[3]}\nRegion size: {region_np.shape}\nDebug: {debug_info}"
209
- else:
210
- info_msg = f"Processed entire image\nImage size: {region_np.shape}\nDebug: {debug_info}"
211
-
212
- return cell_count, overlay_image, info_msg
213
-
214
- except Exception as e:
215
- return 0, None, f"Error occurred: {str(e)}\nDebug info:\n{debug_info if 'debug_info' in locals() else 'No debug info'}"
216
-
217
- # Alternative function for simple image input with coordinate textbox
218
- @spaces.GPU
219
- def segment_with_coords(image, model_choice, crop_coords):
220
- """Segment using regular image input with manual coordinate specification"""
221
- if image is None:
222
- return 0, None, "No image provided"
223
-
224
- # Load the model
225
- model_filename = MODEL_OPTIONS[model_choice]
226
- model_path = hf_hub_download(repo_id=HF_REPO_ID, filename=model_filename)
227
-
228
- if model_filename in loaded_models:
229
- model = loaded_models[model_filename]
230
- else:
231
- model = models.CellposeModel(gpu=True, pretrained_model=model_path)
232
- loaded_models[model_filename] = model
233
-
234
- # Convert PIL Image to numpy array
235
- image_np = np.array(image)
236
-
237
- # Apply crop if coordinates are provided
238
- if crop_coords and crop_coords.strip():
239
- try:
240
- coords = [int(x.strip()) for x in crop_coords.split(',')]
241
- if len(coords) == 4:
242
- x_min, y_min, x_max, y_max = coords
243
- # Ensure coordinates are within image bounds
244
- h, w = image_np.shape[:2]
245
- x_min = max(0, min(x_min, w-1))
246
- y_min = max(0, min(y_min, h-1))
247
- x_max = max(x_min+1, min(x_max, w))
248
- y_max = max(y_min+1, min(y_max, h))
249
-
250
- image_np = image_np[y_min:y_max, x_min:x_max]
251
- except ValueError:
252
- pass # Invalid coordinates, use full image
253
-
254
- # Process image format
255
- if len(image_np.shape) == 2:
256
- image_np = cv2.cvtColor(image_np, cv2.COLOR_GRAY2RGB)
257
- elif len(image_np.shape) == 3 and image_np.shape[2] == 4:
258
- image_np = cv2.cvtColor(image_np, cv2.COLOR_RGBA2RGB)
259
-
260
- # Run Cellpose
261
- masks, flows, styles = model.eval(image_np, diameter=None, channels=[0, 0])
262
-
263
- # Count unique cells
264
- cell_count = len(np.unique(masks)) - 1
265
-
266
- # Create overlay
267
- overlay = image_np.copy().astype(np.float32)
268
-
269
- if masks.max() > 0:
270
- np.random.seed(42)
271
- colors = np.random.randint(0, 255, size=(masks.max() + 1, 3))
272
- colors[0] = [0, 0, 0]
273
-
274
- colored_mask = colors[masks]
275
- alpha = 0.4
276
- overlay = (1 - alpha) * overlay + alpha * colored_mask
277
-
278
- overlay = np.clip(overlay, 0, 255).astype(np.uint8)
279
- overlay_image = Image.fromarray(overlay)
280
-
281
- return cell_count, overlay_image, f"Processed with coordinates: {crop_coords}" if crop_coords else "Processed entire image"
282
-
283
- # Create the Gradio interface with tabs for different input methods
284
- with gr.Blocks(title="Cell Counter with Region Selection") as demo:
285
- gr.Markdown("# Cell Counter with Cellpose - Region Selection")
286
- gr.Markdown("Upload a microscopy image and select a region to count cells using Cellpose segmentation.")
287
-
288
- with gr.Tab("Image Editor (Draw Selection)"):
289
- gr.Markdown("Use the drawing tools to select a region of the image for segmentation.")
290
-
291
- with gr.Row():
292
- with gr.Column():
293
- image_editor = gr.ImageEditor(
294
- label="Draw selection on image",
295
- type="pil",
296
- brush=gr.Brush(colors=["#ff0000"], color_mode="fixed", default_size=20),
297
- eraser=gr.Eraser(default_size=20)
298
- )
299
- model_dropdown1 = gr.Dropdown(
300
- choices=list(MODEL_OPTIONS.keys()),
301
- label="Select Model",
302
- value="Hemocytometer Model"
303
- )
304
- segment_btn1 = gr.Button("Segment Selected Region", variant="primary")
305
-
306
- with gr.Column():
307
- cell_count_output1 = gr.Number(label="Number of Cells")
308
- overlay_output1 = gr.Image(type="pil", label="Segmented Overlay")
309
- info_output1 = gr.Textbox(label="Processing Info")
310
-
311
- segment_btn1.click(
312
- fn=segment_and_count,
313
- inputs=[image_editor, model_dropdown1],
314
- outputs=[cell_count_output1, overlay_output1, info_output1]
315
- )
316
-
317
- with gr.Tab("Manual Coordinates"):
318
- gr.Markdown("Upload an image and specify coordinates manually (format: x_min,y_min,x_max,y_max)")
319
-
320
- with gr.Row():
321
- with gr.Column():
322
- image_input = gr.Image(type="pil", label="Microscopy Image")
323
- model_dropdown2 = gr.Dropdown(
324
- choices=list(MODEL_OPTIONS.keys()),
325
- label="Select Model",
326
- value="Hemocytometer Model"
327
- )
328
- coord_input = gr.Textbox(
329
- label="Crop Coordinates (optional)",
330
- placeholder="e.g., 100,100,400,400",
331
- info="Format: x_min,y_min,x_max,y_max"
332
- )
333
- segment_btn2 = gr.Button("Segment Region", variant="primary")
334
-
335
- with gr.Column():
336
- cell_count_output2 = gr.Number(label="Number of Cells")
337
- overlay_output2 = gr.Image(type="pil", label="Segmented Overlay")
338
- info_output2 = gr.Textbox(label="Processing Info")
339
-
340
- segment_btn2.click(
341
- fn=segment_with_coords,
342
- inputs=[image_input, model_dropdown2, coord_input],
343
- outputs=[cell_count_output2, overlay_output2, info_output2]
344
- )
345
-
346
- if __name__ == "__main__":
347
- demo.launch()
348
-