guohanghui commited on
Commit
aea0ec8
·
verified ·
1 Parent(s): 10bc26c

Update medpy/mcp_output/mcp_plugin/mcp_service.py

Browse files
medpy/mcp_output/mcp_plugin/mcp_service.py CHANGED
@@ -3,6 +3,11 @@ import sys
3
  import numpy as np
4
  import json
5
 
 
 
 
 
 
6
  source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
7
  sys.path.insert(0, source_path)
8
 
@@ -386,6 +391,126 @@ def otsu_threshold_tool(image_data: list) -> dict:
386
  except Exception as e:
387
  return {"success": False, "result": None, "error": str(e)}
388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  @mcp.tool(name="gaussian_gradient_magnitude", description="Compute Gaussian gradient magnitude of image.")
390
  def gaussian_gradient_magnitude_tool(image_data: list, sigma: float = 1.0) -> dict:
391
  """
 
3
  import numpy as np
4
  import json
5
 
6
+ try:
7
+ from scipy import ndimage
8
+ except ImportError:
9
+ ndimage = None
10
+
11
  source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
12
  sys.path.insert(0, source_path)
13
 
 
391
  except Exception as e:
392
  return {"success": False, "result": None, "error": str(e)}
393
 
394
+ @mcp.tool(name="detect_lesions", description="Detect lesion regions in medical images and return detailed location information.")
395
+ def detect_lesions_tool(image_data: list, method: str = "otsu", min_size: int = 10) -> dict:
396
+ """
397
+ Detects lesion regions in medical images and provides detailed location information.
398
+
399
+ This tool automatically segments lesion regions and returns:
400
+ - Lesion locations (coordinates)
401
+ - Lesion sizes (pixel counts)
402
+ - Lesion area percentage
403
+ - Visual description of lesion distribution
404
+
405
+ Parameters:
406
+ - image_data: Input medical image as 2D array (list of lists).
407
+ - method: Segmentation method - "otsu" for automatic thresholding (default) or "manual" for manual threshold.
408
+ - min_size: Minimum lesion size in pixels to filter noise (default: 10).
409
+
410
+ Returns:
411
+ - dict: Contains detailed lesion information including locations, sizes, and distribution.
412
+ """
413
+ try:
414
+ image_array = np.asarray(image_data)
415
+
416
+ # Step 1: Apply Otsu thresholding to detect lesion regions
417
+ threshold = otsu(image_array)
418
+ binary_result = (image_array >= threshold).astype(int)
419
+
420
+ # Step 2: Find lesion regions (connected components)
421
+ lesion_mask = binary_result.astype(bool)
422
+
423
+ # Step 3: Calculate lesion statistics
424
+ total_pixels = lesion_mask.size
425
+ lesion_pixels = np.sum(lesion_mask)
426
+ background_pixels = total_pixels - lesion_pixels
427
+ lesion_percentage = (lesion_pixels / total_pixels * 100) if total_pixels > 0 else 0
428
+
429
+ # Step 4: Find lesion boundaries and bounding boxes
430
+ lesion_coords = []
431
+ lesion_info = []
432
+
433
+ if np.any(lesion_mask):
434
+ # Find all connected components
435
+ if ndimage is not None:
436
+ labeled, num_features = ndimage.label(lesion_mask)
437
+ else:
438
+ # Fallback: use simple detection without connected components
439
+ num_features = 1 if np.any(lesion_mask) else 0
440
+ labeled = lesion_mask.astype(int)
441
+
442
+ for label in range(1, num_features + 1):
443
+ # Get coordinates of this lesion
444
+ lesion_indices = np.where(labeled == label)
445
+ coords = list(zip(lesion_indices[0], lesion_indices[1]))
446
+ lesion_coords.append(coords)
447
+
448
+ # Calculate bounding box
449
+ if coords:
450
+ rows = [c[0] for c in coords]
451
+ cols = [c[1] for c in coords]
452
+ min_row, max_row = min(rows), max(rows)
453
+ min_col, max_col = min(cols), max(cols)
454
+
455
+ lesion_info.append({
456
+ "id": label,
457
+ "pixel_count": len(coords),
458
+ "top_left": [int(min_row), int(min_col)],
459
+ "bottom_right": [int(max_row), int(max_col)],
460
+ "width": int(max_col - min_col + 1),
461
+ "height": int(max_row - min_row + 1),
462
+ "area_percentage": (len(coords) / total_pixels * 100)
463
+ })
464
+
465
+ # Filter by min_size
466
+ lesion_info = [lesion for lesion in lesion_info if lesion["pixel_count"] >= min_size]
467
+
468
+ # Find largest lesion
469
+ if lesion_info:
470
+ largest_lesion = max(lesion_info, key=lambda x: x["pixel_count"])
471
+ lesion_description = f"检测到 {len(lesion_info)} 个病变区域。最大病变位于: 行{largest_lesion['top_left'][0]}-{largest_lesion['bottom_right'][0]}, 列{largest_lesion['top_left'][1]}-{largest_lesion['bottom_right'][1]}, 面积为 {largest_lesion['area_percentage']:.2f}%"
472
+ else:
473
+ lesion_description = "未检测到符合尺寸要求的病变区域"
474
+ else:
475
+ lesion_description = "未检测到病变区域"
476
+
477
+ # Step 5: Calculate intensity statistics for lesion vs background
478
+ lesion_intensities = image_array[lesion_mask]
479
+ background_intensities = image_array[~lesion_mask]
480
+
481
+ result = {
482
+ "success": True,
483
+ "result": {
484
+ "detection_summary": lesion_description,
485
+ "total_lesions": len(lesion_info),
486
+ "lesion_details": lesion_info,
487
+ "statistics": {
488
+ "total_pixels": int(total_pixels),
489
+ "lesion_pixels": int(lesion_pixels),
490
+ "background_pixels": int(background_pixels),
491
+ "lesion_percentage": round(lesion_percentage, 2),
492
+ "threshold_used": round(float(threshold), 4),
493
+ "lesion_intensity_range": {
494
+ "min": float(np.min(lesion_intensities)) if len(lesion_intensities) > 0 else 0,
495
+ "max": float(np.max(lesion_intensities)) if len(lesion_intensities) > 0 else 0,
496
+ "mean": float(np.mean(lesion_intensities)) if len(lesion_intensities) > 0 else 0
497
+ },
498
+ "background_intensity_range": {
499
+ "min": float(np.min(background_intensities)) if len(background_intensities) > 0 else 0,
500
+ "max": float(np.max(background_intensities)) if len(background_intensities) > 0 else 0,
501
+ "mean": float(np.mean(background_intensities)) if len(background_intensities) > 0 else 0
502
+ }
503
+ },
504
+ "binary_mask": binary_result.tolist()
505
+ },
506
+ "error": None
507
+ }
508
+
509
+ return result
510
+
511
+ except Exception as e:
512
+ return {"success": False, "result": None, "error": str(e)}
513
+
514
  @mcp.tool(name="gaussian_gradient_magnitude", description="Compute Gaussian gradient magnitude of image.")
515
  def gaussian_gradient_magnitude_tool(image_data: list, sigma: float = 1.0) -> dict:
516
  """