如何准确计数重叠的细胞Filopodia分割掩码中的丝状体
解决Filopodia二值掩码计数难题的方案
针对丝状体重叠(含结状/环状结构)导致的计数不准确问题,可从拓扑分析优化、预处理分割、深度学习实例分割三个方向解决,以下是具体实现:
一、改进拓扑分析逻辑(修复原代码缺陷)
原代码仅依赖端点计数,无法处理环状结构,需结合分支点、孔洞数修正计数逻辑:
1. 补充分支点检测函数
import numpy as np from skimage.morphology import skeletonize from skimage import measure from collections import Counter def find_endpoints(img): (rows, cols) = np.nonzero(img) skel_coords = [] for (r, c) in zip(rows, cols): col_neigh, row_neigh = np.meshgrid([c-1, c, c+1], [r-1, r, r+1]) col_neigh = col_neigh.astype(int) row_neigh = row_neigh.astype(int) pix_neighbourhood = img[row_neigh, col_neigh].ravel() != 0 # 中心像素非零,邻居仅1个非零 → 端点 if np.sum(pix_neighbourhood) == 2: skel_coords.append((r, c)) return len(skel_coords) def find_branch_points(img): (rows, cols) = np.nonzero(img) branch_coords = [] for (r, c) in zip(rows, cols): col_neigh, row_neigh = np.meshgrid([c-1, c, c+1], [r-1, r, r+1]) col_neigh = col_neigh.astype(int) row_neigh = row_neigh.astype(int) pix_neighbourhood = img[row_neigh, col_neigh].ravel() != 0 # 中心像素非零,邻居≥3个非零 → 分支点 if np.sum(pix_neighbourhood) >= 4: branch_coords.append((r, c)) return len(branch_coords)
2. 结合连通分支、孔洞数的计数函数
def count_filopodia(mask): skel = skeletonize(mask) labeled_skel = measure.label(skel, connectivity=2) props = measure.regionprops(labeled_skel) total_count = 0 for prop in props: region_skel = (labeled_skel == prop.label) n_end = find_endpoints(region_skel) n_branch = find_branch_points(region_skel) # 计算当前连通分支的孔洞数:欧拉数=1-孔洞数(单个分支) n_holes = 1 - prop.euler_number if n_holes == 0: # 树状结构:端点数+分支点数-1(每个端点对应一条独立丝状体,分支点补充分叉) count = n_end + n_branch - 1 else: # 环状结构:树状部分计数 + 孔洞对应的丝状体(环至少对应1条) tree_count = max(n_end + n_branch - 1, 0) count = tree_count + n_holes # 纯环结构(无端点/分支点)至少计为1条 total_count += max(count, 1) return total_count
二、预处理:用分水岭分割减少重叠干扰
对于严重重叠的掩码,先通过距离变换+分水岭分割拆分重叠结构,再计数:
from skimage.segmentation import watershed from skimage.feature import peak_local_max from skimage.morphology import distance_transform_edt def preprocess_overlapped_mask(mask): # 距离变换:计算每个前景像素到背景的距离 dist = distance_transform_edt(mask) # 提取局部极大值作为分割种子 local_max = peak_local_max(dist, indices=False, footprint=np.ones((3,3)), labels=mask) markers = measure.label(local_max) # 分水岭分割拆分重叠区域 segmented_mask = watershed(-dist, markers, mask=mask) return segmented_mask # 使用方式 segmented = preprocess_overlapped_mask(original_mask) total = count_filopodia(segmented)
三、深度学习实例分割(最可靠的复杂场景方案)
针对极端重叠的场景,用Cellpose、Mask R-CNN等模型做实例分割,直接计数独立的Filopodia实例:
Cellpose实现示例
from cellpose import models, io # 加载预训练模型(cyto模型适用于细胞结构,也可自定义训练) model = models.Cellpose(model_type='cyto') # 读取二值掩码或原始图像 img = io.imread('filopodia_mask.png') # 执行实例分割 masks, _, _, _ = model.eval(img, diameter=None, channels=[0,0]) # 计数(减去背景类) filopodia_count = len(np.unique(masks)) - 1
内容的提问来源于stack exchange,提问作者rikyeah
相关产品推荐
相关产品推荐

