Shengxiao0709 commited on
Commit
9d32f50
·
verified ·
1 Parent(s): 79f5edd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -62
app.py CHANGED
@@ -399,102 +399,102 @@ def colorize_mask(mask: np.ndarray, num_colors: int = 512) -> np.ndarray:
399
  # ===== 分割功能 =====
400
  # ===== 彩色 mask 可视化 =====
401
  def colorize_mask(mask: np.ndarray, num_colors: int = 512) -> np.ndarray:
402
- """将实例掩码转换为彩色图像,每个实例一个颜色"""
403
- mask = mask.astype(np.int32)
404
-
405
- def hsv_to_rgb(hh, ss, vv):
406
- i = int(hh * 6.0)
407
- f = hh * 6.0 - i
408
- p = vv * (1.0 - ss)
409
- q = vv * (1.0 - f * ss)
410
- t = vv * (1.0 - (1.0 - f) * ss)
411
  i = i % 6
412
- if i == 0: r, g, b = vv, t, p
413
- elif i == 1: r, g, b = q, vv, p
414
- elif i == 2: r, g, b = p, vv, t
415
- elif i == 3: r, g, b = p, q, vv
416
- elif i == 4: r, g, b = t, p, vv
417
- else: r, g, b = vv, p, q
418
- return int(r*255), int(g*255), int(b*255)
 
 
 
 
 
 
 
 
419
 
420
- palette = [(0, 0, 0)]
421
- for k in range(1, num_colors):
422
- hue = (k % num_colors) / float(num_colors)
423
- palette.append(hsv_to_rgb(hue, 1.0, 0.95))
424
-
425
- color_idx = mask % num_colors
426
  palette_arr = np.array(palette, dtype=np.uint8)
 
427
  return palette_arr[color_idx]
428
 
 
 
 
 
 
 
429
 
 
 
 
 
 
 
 
 
 
 
430
  # ===== 推理 + 实例彩色可视化 =====
431
  def segment_with_choice(use_box_choice, annot_value, mode="Overlay"):
432
- """分割推理 + 可视化(更深颜色、更清晰区分)"""
433
  if annot_value is None or len(annot_value) < 1:
434
- return None, "⚠️ 请先上传图像"
 
435
 
436
  img_path = annot_value[0]
437
  bboxes = annot_value[1] if len(annot_value) > 1 else []
438
 
 
439
  box_array = None
440
  if use_box_choice == "Yes" and bboxes:
441
  box = parse_first_bbox(bboxes)
442
  if box:
443
  xmin, ymin, xmax, ymax = map(int, box)
444
  box_array = [[xmin, ymin, xmax, ymax]]
 
445
 
 
446
  try:
447
- mask = run_seg(SEG_MODEL, img_path, box=box_array, device=SEG_DEVICE)
448
- if mask is None:
449
- return None, "❌ 分割失败"
450
  except Exception as e:
451
- return None, f"❌ 推理错误: {e}"
452
 
 
453
  try:
454
- img = Image.open(img_path).convert("RGB")
455
- img_rgb = img.resize(mask.shape[::-1], resample=Image.BILINEAR)
456
- img_np = np.array(img_rgb, dtype=np.float32)
457
  if img_np.max() > 1.5:
458
- img_np = img_np / 255.0
459
  except Exception as e:
460
- return None, f"❌ 图像处理失败: {e}"
461
 
462
- inst_mask = np.array(mask).astype(np.int32)
463
  unique_ids = np.unique(inst_mask)
464
  num_instances = len(unique_ids[unique_ids != 0])
 
465
 
466
  if num_instances == 0:
467
- return Image.new("RGB", mask.shape[::-1], (255, 200, 200)), "⚠️ 未检测到细胞"
468
 
469
- # ===== 🎨 彩色 mask 生成 =====
470
- color_mask = colorize_mask(inst_mask, num_colors=512).astype(np.float32) / 255.0
 
 
 
471
 
472
- # ===== 🌈 半透明叠加在原图上 =====
473
- overlay = img_np.copy()
474
- alpha = 0.6
475
- blended = (1 - alpha) * overlay + alpha * color_mask
476
 
477
- # ===== 🔶 黄色轮廓线描边每个实例 =====
478
- for inst_id in unique_ids:
479
- if inst_id == 0:
480
- continue
481
- binary_mask = (inst_mask == inst_id).astype(np.uint8)
482
- contours = measure.find_contours(binary_mask, 0.5)
483
- for contour in contours:
484
- contour = contour.astype(np.int32)
485
- for dy in [-1, 0, 1]:
486
- for dx in [-1, 0, 1]:
487
- yy = np.clip(contour[:, 0] + dy, 0, blended.shape[0] - 1).astype(np.int32)
488
- xx = np.clip(contour[:, 1] + dx, 0, blended.shape[1] - 1).astype(np.int32)
489
- blended[yy, xx] = [1.0, 1.0, 0.0] # 黄色边
490
-
491
- blended = np.clip(blended * 255.0, 0, 255).astype(np.uint8)
492
- result_text = f"✅ 检测到 {num_instances} 个细胞"
493
-
494
- if mode == "Instance Mask Only":
495
- return Image.fromarray((color_mask * 255).astype(np.uint8)), result_text
496
-
497
- return Image.fromarray(blended), result_text
498
 
499
  # ===== 计数功能 =====
500
  def count_cells_handler(image_path):
 
399
  # ===== 分割功能 =====
400
  # ===== 彩色 mask 可视化 =====
401
  def colorize_mask(mask: np.ndarray, num_colors: int = 512) -> np.ndarray:
402
+ def hsv_to_rgb(h, s, v):
403
+ i = int(h * 6.0)
404
+ f = h * 6.0 - i
 
 
 
 
 
 
405
  i = i % 6
406
+ p = v * (1 - s)
407
+ q = v * (1 - f * s)
408
+ t = v * (1 - (1 - f) * s)
409
+ if i == 0: r, g, b = v, t, p
410
+ elif i == 1: r, g, b = q, v, p
411
+ elif i == 2: r, g, b = p, v, t
412
+ elif i == 3: r, g, b = p, q, v
413
+ elif i == 4: r, g, b = t, p, v
414
+ else: r, g, b = v, p, q
415
+ return int(r * 255), int(g * 255), int(b * 255)
416
+
417
+ palette = [(0, 0, 0)] # 背景为黑色
418
+ for i in range(1, num_colors):
419
+ h = (i % num_colors) / float(num_colors)
420
+ palette.append(hsv_to_rgb(h, 1.0, 0.95))
421
 
 
 
 
 
 
 
422
  palette_arr = np.array(palette, dtype=np.uint8)
423
+ color_idx = mask % num_colors
424
  return palette_arr[color_idx]
425
 
426
+ def overlay_instances(img, mask, alpha=0.5, cmap_name="tab20"):
427
+ img = img.astype(np.float32)
428
+ if len(img.shape) == 2:
429
+ img = np.stack([img]*3, axis=-1)
430
+ if img.max() > 1.5:
431
+ img = img / 255.0
432
 
433
+ overlay = img.copy()
434
+ cmap = cm.get_cmap(cmap_name, np.max(mask) + 1)
435
+
436
+ for inst_id in np.unique(mask):
437
+ if inst_id == 0:
438
+ continue
439
+ color = np.array(cmap(inst_id)[:3])
440
+ overlay[mask == inst_id] = (1 - alpha) * overlay[mask == inst_id] + alpha * color
441
+
442
+ return overlay
443
  # ===== 推理 + 实例彩色可视化 =====
444
  def segment_with_choice(use_box_choice, annot_value, mode="Overlay"):
445
+ prepare_cuda()
446
  if annot_value is None or len(annot_value) < 1:
447
+ print("❌ No annotation input")
448
+ return None, "请上传图像"
449
 
450
  img_path = annot_value[0]
451
  bboxes = annot_value[1] if len(annot_value) > 1 else []
452
 
453
+ print(f"🖼️ 图像路径: {img_path}")
454
  box_array = None
455
  if use_box_choice == "Yes" and bboxes:
456
  box = parse_first_bbox(bboxes)
457
  if box:
458
  xmin, ymin, xmax, ymax = map(int, box)
459
  box_array = [[xmin, ymin, xmax, ymax]]
460
+ print(f"📦 使用边界框: {box_array}")
461
 
462
+ # === Run model
463
  try:
464
+ mask = run(MODEL, img_path, box=box_array, device=DEVICE)
465
+ print("📏 mask shape:", mask.shape, "unique ids:", np.unique(mask))
 
466
  except Exception as e:
467
+ return None, f"❌ 推理失败: {str(e)}"
468
 
469
+ # === 读取原图
470
  try:
471
+ img = Image.open(img_path).convert("RGB").resize(mask.shape[::-1], resample=Image.BILINEAR)
472
+ img_np = np.array(img).astype(np.float32)
 
473
  if img_np.max() > 1.5:
474
+ img_np /= 255.0
475
  except Exception as e:
476
+ return None, f"❌ 图像读取失败: {str(e)}"
477
 
478
+ inst_mask = mask.astype(np.int32)
479
  unique_ids = np.unique(inst_mask)
480
  num_instances = len(unique_ids[unique_ids != 0])
481
+ print(f"✅ 实例数量: {num_instances}")
482
 
483
  if num_instances == 0:
484
+ return Image.new("RGB", mask.shape[::-1], (255, 0, 0)), "⚠️ 未检测到实例"
485
 
486
+ # === 可视化:Overlay 模式
487
+ if mode == "Overlay":
488
+ overlay = overlay_instances(img_np, inst_mask, alpha=0.5, cmap_name="tab20")
489
+ overlay_img = Image.fromarray((overlay * 255).astype(np.uint8))
490
+ return overlay_img, f"✅ 检测到 {num_instances} 个��胞"
491
 
492
+ # === 可视化:纯彩色 mask
493
+ elif mode == "Instance Mask Only":
494
+ color_mask = colorize_mask(inst_mask, num_colors=512)
495
+ return Image.fromarray(color_mask), f"✅ 检测到 {num_instances} 个细胞"
496
 
497
+ return None, "❓ 无效显示模式"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
 
499
  # ===== 计数功能 =====
500
  def count_cells_handler(image_path):