Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -136,29 +136,11 @@ def colorize_mask(mask: np.ndarray, num_colors: int = 512) -> np.ndarray:
|
|
| 136 |
color_idx = mask % num_colors
|
| 137 |
return palette_arr[color_idx]
|
| 138 |
|
| 139 |
-
def overlay_instances(img, mask, alpha=0.5, cmap_name="tab20"):
|
| 140 |
-
"""叠加实例颜色"""
|
| 141 |
-
img = img.astype(np.float32)
|
| 142 |
-
if len(img.shape) == 2:
|
| 143 |
-
img = np.stack([img]*3, axis=-1)
|
| 144 |
-
if img.max() > 1.5:
|
| 145 |
-
img = img / 255.0
|
| 146 |
-
|
| 147 |
-
overlay = img.copy()
|
| 148 |
-
cmap = cm.get_cmap(cmap_name, np.max(mask) + 1)
|
| 149 |
-
|
| 150 |
-
for inst_id in np.unique(mask):
|
| 151 |
-
if inst_id == 0:
|
| 152 |
-
continue
|
| 153 |
-
color = np.array(cmap(inst_id)[:3])
|
| 154 |
-
overlay[mask == inst_id] = (1 - alpha) * overlay[mask == inst_id] + alpha * color
|
| 155 |
-
|
| 156 |
-
return overlay
|
| 157 |
-
|
| 158 |
# ===== 分割功能 =====
|
| 159 |
def segment_with_choice(use_box_choice, annot_value):
|
| 160 |
-
"""分割主函数 -
|
| 161 |
if annot_value is None or len(annot_value) < 1:
|
|
|
|
| 162 |
return None, None
|
| 163 |
|
| 164 |
img_path = annot_value[0]
|
|
@@ -176,7 +158,7 @@ def segment_with_choice(use_box_choice, annot_value):
|
|
| 176 |
# 运行分割模型
|
| 177 |
try:
|
| 178 |
mask = run_seg(SEG_MODEL, img_path, box=box_array, device=SEG_DEVICE)
|
| 179 |
-
print("📏 mask shape:", mask.shape, "unique
|
| 180 |
except Exception as e:
|
| 181 |
print(f"❌ 推理失败: {str(e)}")
|
| 182 |
return None, None
|
|
@@ -189,26 +171,55 @@ def segment_with_choice(use_box_choice, annot_value):
|
|
| 189 |
|
| 190 |
# 读取原图
|
| 191 |
try:
|
| 192 |
-
img = Image.open(img_path)
|
| 193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
if img_np.max() > 1.5:
|
| 195 |
-
img_np
|
| 196 |
except Exception as e:
|
| 197 |
-
print(f"❌
|
| 198 |
return None, None
|
| 199 |
|
| 200 |
-
|
|
|
|
| 201 |
unique_ids = np.unique(inst_mask)
|
| 202 |
num_instances = len(unique_ids[unique_ids != 0])
|
| 203 |
-
print(f"✅
|
| 204 |
|
| 205 |
if num_instances == 0:
|
|
|
|
| 206 |
return Image.new("RGB", mask.shape[::-1], (255, 0, 0)), None
|
| 207 |
|
| 208 |
-
#
|
| 209 |
-
overlay =
|
| 210 |
-
|
| 211 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
|
| 213 |
# ===== 计数功能 =====
|
| 214 |
def count_cells_handler(image_path):
|
|
|
|
| 136 |
color_idx = mask % num_colors
|
| 137 |
return palette_arr[color_idx]
|
| 138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
# ===== 分割功能 =====
|
| 140 |
def segment_with_choice(use_box_choice, annot_value):
|
| 141 |
+
"""分割主函数 - 每个实例不同颜色+轮廓"""
|
| 142 |
if annot_value is None or len(annot_value) < 1:
|
| 143 |
+
print("❌ No annotation input")
|
| 144 |
return None, None
|
| 145 |
|
| 146 |
img_path = annot_value[0]
|
|
|
|
| 158 |
# 运行分割模型
|
| 159 |
try:
|
| 160 |
mask = run_seg(SEG_MODEL, img_path, box=box_array, device=SEG_DEVICE)
|
| 161 |
+
print("📏 mask shape:", mask.shape, "dtype:", mask.dtype, "unique:", np.unique(mask))
|
| 162 |
except Exception as e:
|
| 163 |
print(f"❌ 推理失败: {str(e)}")
|
| 164 |
return None, None
|
|
|
|
| 171 |
|
| 172 |
# 读取原图
|
| 173 |
try:
|
| 174 |
+
img = Image.open(img_path)
|
| 175 |
+
print("📷 Image mode:", img.mode, "size:", img.size)
|
| 176 |
+
except Exception as e:
|
| 177 |
+
print(f"❌ Failed to open image: {e}")
|
| 178 |
+
return None, None
|
| 179 |
+
|
| 180 |
+
try:
|
| 181 |
+
img_rgb = img.convert("RGB").resize(mask.shape[::-1], resample=Image.BILINEAR)
|
| 182 |
+
img_np = np.array(img_rgb, dtype=np.float32)
|
| 183 |
if img_np.max() > 1.5:
|
| 184 |
+
img_np = img_np / 255.0
|
| 185 |
except Exception as e:
|
| 186 |
+
print(f"❌ Error in image conversion/resizing: {e}")
|
| 187 |
return None, None
|
| 188 |
|
| 189 |
+
mask_np = np.array(mask)
|
| 190 |
+
inst_mask = mask_np.astype(np.int32)
|
| 191 |
unique_ids = np.unique(inst_mask)
|
| 192 |
num_instances = len(unique_ids[unique_ids != 0])
|
| 193 |
+
print(f"✅ Instance IDs found: {unique_ids}, Total instances: {num_instances}")
|
| 194 |
|
| 195 |
if num_instances == 0:
|
| 196 |
+
print("⚠️ No instance found, returning dummy red image")
|
| 197 |
return Image.new("RGB", mask.shape[::-1], (255, 0, 0)), None
|
| 198 |
|
| 199 |
+
# ==== Color Overlay (每个实例一个颜色) ====
|
| 200 |
+
overlay = img_np.copy()
|
| 201 |
+
alpha = 0.5
|
| 202 |
+
cmap = cm.get_cmap("nipy_spectral", num_instances + 1)
|
| 203 |
+
|
| 204 |
+
for inst_id in np.unique(inst_mask):
|
| 205 |
+
if inst_id == 0:
|
| 206 |
+
continue
|
| 207 |
+
binary_mask = (inst_mask == inst_id).astype(np.uint8)
|
| 208 |
+
color = np.array(cmap(inst_id / (num_instances + 1))[:3]) # RGB only, ignore alpha
|
| 209 |
+
overlay[binary_mask == 1] = (1 - alpha) * overlay[binary_mask == 1] + alpha * color
|
| 210 |
+
|
| 211 |
+
# 绘制轮廓
|
| 212 |
+
contours = measure.find_contours(binary_mask, 0.5)
|
| 213 |
+
for contour in contours:
|
| 214 |
+
contour = contour.astype(np.int32)
|
| 215 |
+
# 确保坐标在范围内
|
| 216 |
+
valid_y = np.clip(contour[:, 0], 0, overlay.shape[0] - 1)
|
| 217 |
+
valid_x = np.clip(contour[:, 1], 0, overlay.shape[1] - 1)
|
| 218 |
+
overlay[valid_y, valid_x] = [1.0, 1.0, 0.0] # 黄色轮廓
|
| 219 |
+
|
| 220 |
+
overlay = np.clip(overlay * 255.0, 0, 255).astype(np.uint8)
|
| 221 |
+
|
| 222 |
+
return Image.fromarray(overlay), temp_mask_file.name
|
| 223 |
|
| 224 |
# ===== 计数功能 =====
|
| 225 |
def count_cells_handler(image_path):
|