Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -429,32 +429,27 @@ def colorize_mask(mask: np.ndarray, num_colors: int = 512) -> np.ndarray:
|
|
| 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 |
-
print("❌ No annotation input")
|
| 435 |
return None, "⚠️ 请先上传图像"
|
| 436 |
|
| 437 |
img_path = annot_value[0]
|
| 438 |
bboxes = annot_value[1] if len(annot_value) > 1 else []
|
| 439 |
|
| 440 |
-
print(f"🖼️ Image path: {img_path}")
|
| 441 |
box_array = None
|
| 442 |
if use_box_choice == "Yes" and bboxes:
|
| 443 |
box = parse_first_bbox(bboxes)
|
| 444 |
if box:
|
| 445 |
xmin, ymin, xmax, ymax = map(int, box)
|
| 446 |
box_array = [[xmin, ymin, xmax, ymax]]
|
| 447 |
-
print(f"📦 Using box: {box_array}")
|
| 448 |
|
| 449 |
try:
|
| 450 |
-
# 调用分割模型
|
| 451 |
mask = run_seg(SEG_MODEL, img_path, box=box_array, device=SEG_DEVICE)
|
| 452 |
-
|
|
|
|
| 453 |
except Exception as e:
|
| 454 |
-
|
| 455 |
-
return None, f"分割失败: {str(e)}"
|
| 456 |
|
| 457 |
-
# 读取原图
|
| 458 |
try:
|
| 459 |
img = Image.open(img_path).convert("RGB")
|
| 460 |
img_rgb = img.resize(mask.shape[::-1], resample=Image.BILINEAR)
|
|
@@ -462,50 +457,44 @@ def segment_with_choice(use_box_choice, annot_value, mode="Overlay"):
|
|
| 462 |
if img_np.max() > 1.5:
|
| 463 |
img_np = img_np / 255.0
|
| 464 |
except Exception as e:
|
| 465 |
-
|
| 466 |
-
return None, f"图像读取失败: {str(e)}"
|
| 467 |
|
| 468 |
-
|
| 469 |
-
mask_np = np.array(mask)
|
| 470 |
-
inst_mask = mask_np.astype(np.int32)
|
| 471 |
unique_ids = np.unique(inst_mask)
|
| 472 |
num_instances = len(unique_ids[unique_ids != 0])
|
| 473 |
-
print(f"✅ Instance IDs found: {unique_ids}, Total instances: {num_instances}")
|
| 474 |
|
| 475 |
if num_instances == 0:
|
| 476 |
-
|
| 477 |
-
return Image.new("RGB", mask.shape[::-1], (255, 0, 0)), "⚠️ 未检测到细胞"
|
| 478 |
|
| 479 |
-
# ==== 🎨
|
|
|
|
|
|
|
|
|
|
| 480 |
overlay = img_np.copy()
|
| 481 |
-
alpha = 0.
|
| 482 |
-
|
| 483 |
|
| 484 |
-
|
|
|
|
| 485 |
if inst_id == 0:
|
| 486 |
continue
|
| 487 |
binary_mask = (inst_mask == inst_id).astype(np.uint8)
|
| 488 |
-
color = np.array(cmap(inst_id / (num_instances + 1))[:3])
|
| 489 |
-
overlay[binary_mask == 1] = (1 - alpha) * overlay[binary_mask == 1] + alpha * color
|
| 490 |
-
|
| 491 |
-
# 🟡 绘制粗黄色轮廓
|
| 492 |
contours = measure.find_contours(binary_mask, 0.5)
|
| 493 |
for contour in contours:
|
| 494 |
contour = contour.astype(np.int32)
|
| 495 |
for dy in [-1, 0, 1]:
|
| 496 |
for dx in [-1, 0, 1]:
|
| 497 |
-
yy = np.clip(contour[:, 0] + dy, 0,
|
| 498 |
-
xx = np.clip(contour[:, 1] + dx, 0,
|
| 499 |
-
|
| 500 |
|
| 501 |
-
|
| 502 |
result_text = f"✅ 检测到 {num_instances} 个细胞"
|
| 503 |
|
| 504 |
if mode == "Instance Mask Only":
|
| 505 |
-
|
| 506 |
-
return Image.fromarray(colorize_mask(inst_mask, num_colors=512)), result_text
|
| 507 |
|
| 508 |
-
return Image.fromarray(
|
| 509 |
|
| 510 |
# ===== 计数功能 =====
|
| 511 |
def count_cells_handler(image_path):
|
|
|
|
| 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)
|
|
|
|
| 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):
|