paulnhuu174 commited on
Commit
83e18b3
·
verified ·
1 Parent(s): 9a1dfda

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -94
app.py CHANGED
@@ -21,6 +21,10 @@ try:
21
  except ImportError:
22
  YOLO_AVAILABLE = False
23
 
 
 
 
 
24
  # Category names mapping (0-27)
25
  CATEGORY_NAMES = {
26
  0: "Nucleoplasm", 1: "Nuclear membrane", 2: "Nucleoli",
@@ -60,13 +64,13 @@ def extract_image_id(filename):
60
  return name_without_ext.replace(color, '')
61
  return name_without_ext
62
 
63
- def load_csv_file(csv_file):
64
- """Load and parse CSV file."""
65
- if csv_file is None:
66
- return "No CSV file uploaded", ""
67
 
68
  try:
69
- state.csv_data = pd.read_csv(csv_file.name)
70
  state.image_categories = {}
71
 
72
  for _, row in state.csv_data.iterrows():
@@ -79,36 +83,31 @@ def load_csv_file(csv_file):
79
  'indices': category_indices,
80
  'names': category_names
81
  }
82
-
83
- return f"✅ Loaded CSV with {len(state.csv_data)} entries", ""
84
  except Exception as e:
85
- return f" Error: {str(e)}", ""
86
 
87
- def scan_folder(folder_path):
88
- """Scan folder for images."""
89
- if not folder_path or not os.path.exists(folder_path):
90
- return None, "❌ Folder not found", "0 images"
91
-
92
- if not os.path.isdir(folder_path):
93
- return None, "❌ Not a directory", "0 images"
94
 
95
  try:
96
  extensions = {'.png', '.jpg', '.jpeg', '.tif', '.tiff', '.bmp'}
97
  state.image_files = []
98
 
99
- for f in sorted(Path(folder_path).iterdir()):
100
  if f.suffix.lower() in extensions:
101
  state.image_files.append(str(f))
102
 
103
  if len(state.image_files) == 0:
104
- return None, "⚠️ No images found", "0 images"
105
 
106
  # Generate gallery
107
  gallery_items = [(img, os.path.basename(img)) for img in state.image_files]
108
-
109
- return gallery_items, f"✅ Found {len(state.image_files)} images", f"{len(state.image_files)} images"
110
  except Exception as e:
111
- return None, f" Error: {str(e)}", "0 images"
 
112
 
113
  def prepare_image_for_yolo(image):
114
  """Convert grayscale to RGB for YOLO."""
@@ -124,7 +123,7 @@ def prepare_image_for_yolo(image):
124
  def select_image_from_gallery(evt: gr.SelectData):
125
  """Handle image selection from gallery."""
126
  if not state.image_files or evt.index >= len(state.image_files):
127
- return None, "Invalid selection", "", gr.update(choices=[])
128
 
129
  state.selected_image = state.image_files[evt.index]
130
 
@@ -147,9 +146,9 @@ def select_image_from_gallery(evt: gr.SelectData):
147
  # Show original image
148
  fig = create_visualization(show_numbers=False)
149
 
150
- return fig, f" {os.path.basename(state.selected_image)}", categories_text, gr.update(choices=[])
151
  except Exception as e:
152
- return None, f"Load failed: {str(e)}", "", gr.update(choices=[])
153
 
154
  def get_image_categories():
155
  """Get category information for selected image."""
@@ -160,7 +159,7 @@ def get_image_categories():
160
  categories = state.image_categories.get(img_id)
161
 
162
  if categories:
163
- result = "🏷️ Image Categories\n" + "=" * 30 + "\n"
164
  for idx, name in zip(categories['indices'], categories['names']):
165
  result += f"[{idx}] {name}\n"
166
  return result
@@ -169,10 +168,10 @@ def get_image_categories():
169
  def run_cellpose_segmentation(model_type, diameter, use_gpu):
170
  """Run Cellpose segmentation."""
171
  if state.current_image is None:
172
- return None, "⚠️ No image selected", gr.update(choices=[])
173
 
174
  if not CELLPOSE_AVAILABLE:
175
- return None, "Cellpose not installed", gr.update(choices=[])
176
 
177
  try:
178
  with warnings.catch_warnings():
@@ -204,20 +203,20 @@ def run_cellpose_segmentation(model_type, diameter, use_gpu):
204
  )
205
 
206
  if state.masks is None or state.masks.max() == 0:
207
- return None, "⚠️ No cells detected", gr.update(choices=[])
208
 
209
  return finalize_segmentation()
210
 
211
  except Exception as e:
212
- return None, f"Error: {str(e)}", gr.update(choices=[])
213
 
214
  def run_yolo_segmentation(model_path, confidence, iou, use_gpu):
215
  """Run YOLO segmentation."""
216
  if state.current_image is None:
217
- return None, "⚠️ No image selected", gr.update(choices=[])
218
 
219
  if not YOLO_AVAILABLE:
220
- return None, "YOLO not installed", gr.update(choices=[])
221
 
222
  try:
223
  with warnings.catch_warnings():
@@ -244,12 +243,12 @@ def run_yolo_segmentation(model_path, confidence, iou, use_gpu):
244
  state.masks = yolo_results_to_masks(results[0])
245
 
246
  if state.masks is None or state.masks.max() == 0:
247
- return None, "⚠️ No objects detected", gr.update(choices=[])
248
 
249
  return finalize_segmentation()
250
 
251
  except Exception as e:
252
- return None, f"Error: {str(e)}", gr.update(choices=[])
253
 
254
  def yolo_results_to_masks(result):
255
  """Convert YOLO results to mask format."""
@@ -283,10 +282,10 @@ def finalize_segmentation():
283
  # Create cell list
284
  cell_list = [f"Cell {prop.label} | Area: {prop.area}px²" for prop in state.cell_properties]
285
 
286
- return fig, f"{state.masks.max()} cells detected", gr.update(choices=cell_list)
287
 
288
  except Exception as e:
289
- return None, f"Error: {str(e)}", gr.update(choices=[])
290
 
291
  def create_visualization(show_numbers=False, highlight_cell=None):
292
  """Create segmentation visualization."""
@@ -402,15 +401,18 @@ def select_cell(cell_choice):
402
  # Find cell properties
403
  for prop in state.cell_properties:
404
  if prop.label == cell_id:
405
- details = f"📊 Cell {cell_id}\n"
406
- details += "" * 25 + "\n"
407
  details += f"Area: {prop.area}px²\n"
408
  details += f"Centroid: ({prop.centroid[1]:.0f}, {prop.centroid[0]:.0f})\n"
409
  details += f"Eccentricity: {prop.eccentricity:.3f}\n"
410
  details += f"Solidity: {prop.solidity:.3f}\n"
411
  details += f"Intensity: {prop.mean_intensity:.1f}\n"
412
- details += f"Major Axis: {prop.major_axis_length:.1f}px\n"
413
- details += f"Minor Axis: {prop.minor_axis_length:.1f}px\n"
 
 
 
414
 
415
  # Update visualization
416
  fig = create_visualization(show_numbers=False, highlight_cell=cell_id)
@@ -418,7 +420,7 @@ def select_cell(cell_choice):
418
 
419
  return None, "Cell not found"
420
  except Exception as e:
421
- return None, f"Error: {str(e)}"
422
 
423
  def run_segmentation(method, cp_model, diameter, yolo_model, confidence, iou, use_gpu):
424
  """Run segmentation based on selected method."""
@@ -430,7 +432,7 @@ def run_segmentation(method, cp_model, diameter, yolo_model, confidence, iou, us
430
  def save_results():
431
  """Save segmentation results."""
432
  if state.masks is None:
433
- return None, "⚠️ No results to save"
434
 
435
  try:
436
  import tempfile
@@ -451,41 +453,31 @@ def save_results():
451
  f"{prop.centroid[0]:.1f},{prop.eccentricity:.3f},"
452
  f"{prop.solidity:.3f},{prop.mean_intensity:.1f}\n")
453
 
454
- return [mask_path, csv_path], "Results saved"
455
  except Exception as e:
456
- return None, f"Error: {str(e)}"
 
 
 
 
457
 
458
  # Create Gradio interface
459
  with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
460
- gr.Markdown("# 🔬 Cell Segmentation Application")
461
 
462
  with gr.Row():
463
- # LEFT COLUMN - Image Browser
464
  with gr.Column(scale=1):
465
- gr.Markdown("### 📁 Image Browser")
466
-
467
- folder_input = gr.Textbox(
468
- label="Folder Path",
469
- value="./imgs",
470
- placeholder="Enter folder path"
471
- )
472
 
473
- with gr.Row():
474
- scan_button = gr.Button("Scan Folder", variant="primary")
475
-
476
- image_count = gr.Textbox(label="Images Found", value="0 images", interactive=False)
477
-
478
- csv_file = gr.File(label="Upload CSV (optional)", file_types=[".csv"])
479
- csv_status = gr.Textbox(label="CSV Status", interactive=False, visible=False)
480
-
481
- # Image gallery (thumbnails)
482
  image_gallery = gr.Gallery(
483
- label="Click image to select",
 
484
  show_label=True,
485
  elem_id="gallery",
486
  columns=1,
487
  rows=None,
488
- height=400,
489
  object_fit="contain"
490
  )
491
 
@@ -493,7 +485,7 @@ with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
493
 
494
  # CENTER COLUMN - Image View
495
  with gr.Column(scale=2):
496
- gr.Markdown("### 🖼️ Image View")
497
 
498
  with gr.Row():
499
  view_mode = gr.Radio(
@@ -507,7 +499,7 @@ with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
507
 
508
  # RIGHT COLUMN - Controls & Results
509
  with gr.Column(scale=1):
510
- gr.Markdown("### ⚙️ Segmentation Settings")
511
 
512
  method = gr.Radio(
513
  ["Cellpose", "YOLO"],
@@ -532,9 +524,9 @@ with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
532
 
533
  use_gpu = gr.Checkbox(label="Use GPU", value=False)
534
 
535
- run_button = gr.Button("🔬 Run Segmentation", variant="primary", size="lg")
536
 
537
- gr.Markdown("### 🔬 Detected Cells")
538
 
539
  cell_dropdown = gr.Dropdown(
540
  label="Select Cell",
@@ -542,14 +534,14 @@ with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
542
  interactive=True
543
  )
544
 
545
- gr.Markdown("### 📊 Cell Details")
546
  cell_details = gr.Textbox(
547
  label="",
548
  lines=12,
549
  interactive=False
550
  )
551
 
552
- save_button = gr.Button("💾 Save Results", variant="secondary")
553
  output_files = gr.File(label="Download", file_count="multiple")
554
 
555
  # Event handlers
@@ -561,18 +553,6 @@ with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
561
 
562
  method.change(toggle_method, inputs=[method], outputs=[cellpose_group, yolo_group])
563
 
564
- scan_button.click(
565
- scan_folder,
566
- inputs=[folder_input],
567
- outputs=[image_gallery, status_text, image_count]
568
- )
569
-
570
- csv_file.change(
571
- load_csv_file,
572
- inputs=[csv_file],
573
- outputs=[csv_status, cell_details]
574
- )
575
-
576
  image_gallery.select(
577
  select_image_from_gallery,
578
  outputs=[image_display, status_text, cell_details, cell_dropdown]
@@ -606,20 +586,6 @@ with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
606
  save_results,
607
  outputs=[output_files, status_text]
608
  )
609
-
610
- gr.Markdown("""
611
- ### 📝 Instructions:
612
- 1. Enter folder path and click "Scan Folder"
613
- 2. Click on image thumbnail in gallery to select
614
- 3. (Optional) Upload train.csv for category information
615
- 4. Choose segmentation method (Cellpose or YOLO)
616
- 5. Configure parameters
617
- 6. Click "Run Segmentation"
618
- 7. View results in overlay mode
619
- 8. Select cells from dropdown to view details and highlight
620
- 9. Toggle "Show Cell Numbers" to display labels
621
- 10. Save results to download masks and measurements
622
- """)
623
 
624
  if __name__ == "__main__":
625
  demo.launch(share=False)
 
21
  except ImportError:
22
  YOLO_AVAILABLE = False
23
 
24
+ # Configuration
25
+ IMAGE_FOLDER = "./imgs"
26
+ CSV_FILE = "train.csv"
27
+
28
  # Category names mapping (0-27)
29
  CATEGORY_NAMES = {
30
  0: "Nucleoplasm", 1: "Nuclear membrane", 2: "Nucleoli",
 
64
  return name_without_ext.replace(color, '')
65
  return name_without_ext
66
 
67
+ def load_csv_data():
68
+ """Auto-load CSV file."""
69
+ if not os.path.exists(CSV_FILE):
70
+ return
71
 
72
  try:
73
+ state.csv_data = pd.read_csv(CSV_FILE)
74
  state.image_categories = {}
75
 
76
  for _, row in state.csv_data.iterrows():
 
83
  'indices': category_indices,
84
  'names': category_names
85
  }
 
 
86
  except Exception as e:
87
+ print(f"Could not load CSV: {e}")
88
 
89
+ def scan_folder():
90
+ """Auto-scan folder for images."""
91
+ if not os.path.exists(IMAGE_FOLDER) or not os.path.isdir(IMAGE_FOLDER):
92
+ return None
 
 
 
93
 
94
  try:
95
  extensions = {'.png', '.jpg', '.jpeg', '.tif', '.tiff', '.bmp'}
96
  state.image_files = []
97
 
98
+ for f in sorted(Path(IMAGE_FOLDER).iterdir()):
99
  if f.suffix.lower() in extensions:
100
  state.image_files.append(str(f))
101
 
102
  if len(state.image_files) == 0:
103
+ return None
104
 
105
  # Generate gallery
106
  gallery_items = [(img, os.path.basename(img)) for img in state.image_files]
107
+ return gallery_items
 
108
  except Exception as e:
109
+ print(f"Scan error: {e}")
110
+ return None
111
 
112
  def prepare_image_for_yolo(image):
113
  """Convert grayscale to RGB for YOLO."""
 
123
  def select_image_from_gallery(evt: gr.SelectData):
124
  """Handle image selection from gallery."""
125
  if not state.image_files or evt.index >= len(state.image_files):
126
+ return None, "Invalid selection", "", gr.update(choices=[])
127
 
128
  state.selected_image = state.image_files[evt.index]
129
 
 
146
  # Show original image
147
  fig = create_visualization(show_numbers=False)
148
 
149
+ return fig, f"Loaded: {os.path.basename(state.selected_image)}", categories_text, gr.update(choices=[])
150
  except Exception as e:
151
+ return None, f"Load failed: {str(e)}", "", gr.update(choices=[])
152
 
153
  def get_image_categories():
154
  """Get category information for selected image."""
 
159
  categories = state.image_categories.get(img_id)
160
 
161
  if categories:
162
+ result = "Image Categories\n" + "=" * 30 + "\n"
163
  for idx, name in zip(categories['indices'], categories['names']):
164
  result += f"[{idx}] {name}\n"
165
  return result
 
168
  def run_cellpose_segmentation(model_type, diameter, use_gpu):
169
  """Run Cellpose segmentation."""
170
  if state.current_image is None:
171
+ return None, "No image selected", gr.update(choices=[])
172
 
173
  if not CELLPOSE_AVAILABLE:
174
+ return None, "Cellpose not installed", gr.update(choices=[])
175
 
176
  try:
177
  with warnings.catch_warnings():
 
203
  )
204
 
205
  if state.masks is None or state.masks.max() == 0:
206
+ return None, "No cells detected", gr.update(choices=[])
207
 
208
  return finalize_segmentation()
209
 
210
  except Exception as e:
211
+ return None, f"Error: {str(e)}", gr.update(choices=[])
212
 
213
  def run_yolo_segmentation(model_path, confidence, iou, use_gpu):
214
  """Run YOLO segmentation."""
215
  if state.current_image is None:
216
+ return None, "No image selected", gr.update(choices=[])
217
 
218
  if not YOLO_AVAILABLE:
219
+ return None, "YOLO not installed", gr.update(choices=[])
220
 
221
  try:
222
  with warnings.catch_warnings():
 
243
  state.masks = yolo_results_to_masks(results[0])
244
 
245
  if state.masks is None or state.masks.max() == 0:
246
+ return None, "No objects detected", gr.update(choices=[])
247
 
248
  return finalize_segmentation()
249
 
250
  except Exception as e:
251
+ return None, f"Error: {str(e)}", gr.update(choices=[])
252
 
253
  def yolo_results_to_masks(result):
254
  """Convert YOLO results to mask format."""
 
282
  # Create cell list
283
  cell_list = [f"Cell {prop.label} | Area: {prop.area}px²" for prop in state.cell_properties]
284
 
285
+ return fig, f"{state.masks.max()} cells detected", gr.update(choices=cell_list)
286
 
287
  except Exception as e:
288
+ return None, f"Error: {str(e)}", gr.update(choices=[])
289
 
290
  def create_visualization(show_numbers=False, highlight_cell=None):
291
  """Create segmentation visualization."""
 
401
  # Find cell properties
402
  for prop in state.cell_properties:
403
  if prop.label == cell_id:
404
+ details = f"Cell {cell_id}\n"
405
+ details += "=" * 25 + "\n"
406
  details += f"Area: {prop.area}px²\n"
407
  details += f"Centroid: ({prop.centroid[1]:.0f}, {prop.centroid[0]:.0f})\n"
408
  details += f"Eccentricity: {prop.eccentricity:.3f}\n"
409
  details += f"Solidity: {prop.solidity:.3f}\n"
410
  details += f"Intensity: {prop.mean_intensity:.1f}\n"
411
+
412
+ # Add categories if available
413
+ categories = get_image_categories()
414
+ if categories:
415
+ details += "\n" + categories
416
 
417
  # Update visualization
418
  fig = create_visualization(show_numbers=False, highlight_cell=cell_id)
 
420
 
421
  return None, "Cell not found"
422
  except Exception as e:
423
+ return None, f"Error: {str(e)}"
424
 
425
  def run_segmentation(method, cp_model, diameter, yolo_model, confidence, iou, use_gpu):
426
  """Run segmentation based on selected method."""
 
432
  def save_results():
433
  """Save segmentation results."""
434
  if state.masks is None:
435
+ return None, "No results to save"
436
 
437
  try:
438
  import tempfile
 
453
  f"{prop.centroid[0]:.1f},{prop.eccentricity:.3f},"
454
  f"{prop.solidity:.3f},{prop.mean_intensity:.1f}\n")
455
 
456
+ return [mask_path, csv_path], "Results saved"
457
  except Exception as e:
458
+ return None, f"Error: {str(e)}"
459
+
460
+ # Initialize: Load CSV and scan folder
461
+ load_csv_data()
462
+ initial_gallery = scan_folder()
463
 
464
  # Create Gradio interface
465
  with gr.Blocks(title="Cell Segmentation Tool", theme=gr.themes.Soft()) as demo:
466
+ gr.Markdown("# Cell Segmentation Application")
467
 
468
  with gr.Row():
469
+ # LEFT COLUMN - Image Gallery
470
  with gr.Column(scale=1):
471
+ gr.Markdown("### Image Gallery")
 
 
 
 
 
 
472
 
 
 
 
 
 
 
 
 
 
473
  image_gallery = gr.Gallery(
474
+ value=initial_gallery,
475
+ label=f"{len(state.image_files)} images" if state.image_files else "No images",
476
  show_label=True,
477
  elem_id="gallery",
478
  columns=1,
479
  rows=None,
480
+ height=600,
481
  object_fit="contain"
482
  )
483
 
 
485
 
486
  # CENTER COLUMN - Image View
487
  with gr.Column(scale=2):
488
+ gr.Markdown("### Image View")
489
 
490
  with gr.Row():
491
  view_mode = gr.Radio(
 
499
 
500
  # RIGHT COLUMN - Controls & Results
501
  with gr.Column(scale=1):
502
+ gr.Markdown("### Segmentation Settings")
503
 
504
  method = gr.Radio(
505
  ["Cellpose", "YOLO"],
 
524
 
525
  use_gpu = gr.Checkbox(label="Use GPU", value=False)
526
 
527
+ run_button = gr.Button("Run Segmentation", variant="primary", size="lg")
528
 
529
+ gr.Markdown("### Detected Cells")
530
 
531
  cell_dropdown = gr.Dropdown(
532
  label="Select Cell",
 
534
  interactive=True
535
  )
536
 
537
+ gr.Markdown("### Cell Details")
538
  cell_details = gr.Textbox(
539
  label="",
540
  lines=12,
541
  interactive=False
542
  )
543
 
544
+ save_button = gr.Button("Save Results", variant="secondary")
545
  output_files = gr.File(label="Download", file_count="multiple")
546
 
547
  # Event handlers
 
553
 
554
  method.change(toggle_method, inputs=[method], outputs=[cellpose_group, yolo_group])
555
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  image_gallery.select(
557
  select_image_from_gallery,
558
  outputs=[image_display, status_text, cell_details, cell_dropdown]
 
586
  save_results,
587
  outputs=[output_files, status_text]
588
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
 
590
  if __name__ == "__main__":
591
  demo.launch(share=False)