细胞核分割程序中背景噪声残留问题的优化咨询
细胞核Mask分割优化方案
问题背景
需要对目标图像中的细胞核生成Mask以进行计数,当前采用颜色处理+K-means分割+轮廓检测的流程,但生成的Mask存在大量背景噪声,残留基质和部分细胞质,分割效果未达预期。
当前实现代码
import sys import os import cv2 import copy import numpy as np #Load images (600x600x3) img = cv2.imread("corte3031malo.tif") if img is None: print('The file doesn\'t contain an image') sys.exit(1) WIDTH = img.shape[1] HEIGHT = img.shape[0] #Preprocessing lab_img = cv2.cvtColor(img, cv2.COLOR_RGB2LAB) clahe = cv2.createCLAHE(clipLimit =2.0, tileGridSize=(8,8)) cl_img_l = clahe.apply(lab_img[:,:,0]) #Segmentation # Define criteria = ( type, max_iter = 10 , epsilon = 1.0 ) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) # Set flags (Just to avoid line break in the code) flags = cv2.KMEANS_RANDOM_CENTERS data = np.float32(cl_img_l.flatten().reshape(cl_img_l.shape[0]*cl_img_l.shape[1])) # reshaping the image to accomodate it as a data matrix K = 3 #Nuclei, background and others compactness,labels,centers = cv2.kmeans(data,K,None,criteria,10,flags) centers = np.uint8(centers) clustered_image = centers[labels.flatten()] clustered_image = clustered_image.reshape(img[:,:,0].shape) print('centers: ') for k in range(0,K): # Show in console the BGR values of these centers print(centers[k]) cv2.imshow("clustered image",clustered_image) cv2.waitKey(0) print('Compactness = ', compactness) # Show in console the measurement of how compact are the clusters around their centroids print('Compactness*K = ', compactness*K) # Using a simple measurement to find when to stop increasing clusters (Colors) #Contours _, nuclei = cv2.threshold(clustered_image, np.max(centers)-1, 255,cv2.THRESH_BINARY) contours, _ = cv2.findContours(nuclei, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) img_contours = np.zeros((HEIGHT,WIDTH), np.uint8) for i, c in enumerate(contours): area = cv2.contourArea(c) if 50 < area < 500 | True: cv2.drawContours(img_contours, contours, i, (255), thickness=cv2.FILLED) cv2.imshow("contours",img_contours) cv2.waitKey(0) #Mask _, mask = cv2.threshold(img_contours, np.max(centers)-1, 255,cv2.THRESH_BINARY) masked = cv2.bitwise_and(img, img, mask=mask) cv2.imshow("Masked", masked) cv2.waitKey(0)
优化方案
一、预处理阶段优化
- 切换至更适配的颜色通道
H&E染色的细胞核呈蓝紫色,在BGR格式的蓝色通道中对比度最高,建议替换当前的LAB-L分量:# 改用蓝色通道进行预处理 blue_channel = img[:, :, 0] # cv2.imread默认读取为BGR,蓝色为第0通道 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) cl_img_l = clahe.apply(blue_channel) - 添加去噪步骤
在CLAHE增强后加入高斯/中值滤波,消除背景颗粒噪声:# CLAHE后添加高斯模糊去噪 cl_img_l = cv2.GaussianBlur(cl_img_l, (3,3), 0) # 或中值滤波(更适合去除椒盐噪声) # cl_img_l = cv2.medianBlur(cl_img_l, 3)
二、K-means分割阶段优化
- 使用多通道特征聚类
单通道灰度信息不足以区分细胞核、细胞质和基质,建议结合多通道特征(如LAB三通道):# 改用LAB三通道数据进行K-means lab_img = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) lab_img[:,:,0] = clahe.apply(lab_img[:,:,0]) # 重塑为N×3的样本矩阵(每个样本对应一个像素的三个通道值) data = np.float32(lab_img.reshape(-1, 3)) - 调整K值与簇筛选逻辑
K=3可能不足以区分多类组织,尝试K=4或K=5,聚类完成后通过亮度特征手动筛选细胞核簇(细胞核通常是较暗的簇):K = 4 compactness,labels,centers = cv2.kmeans(data,K,None,criteria,10,flags) # 按LAB-L分量排序,暗簇在前(对应细胞核) centers_sorted = sorted(enumerate(centers), key=lambda x: x[1][0]) nucleus_label = centers_sorted[0][0] # 生成细胞核掩码 clustered_image = labels.reshape(cl_img_l.shape) nuclei_mask = np.where(clustered_image == nucleus_label, 255, 0).astype(np.uint8)
三、后处理阶段优化
- 修复轮廓筛选逻辑
当前代码中50 < area < 500 | True逻辑无效(| True导致条件恒成立),需替换为基于面积+圆度的筛选:img_contours = np.zeros((HEIGHT,WIDTH), np.uint8) for i, c in enumerate(contours): area = cv2.contourArea(c) perimeter = cv2.arcLength(c, True) if perimeter == 0: continue # 计算圆度(细胞核近似圆形,圆度越接近1越圆) circularity = 4 * np.pi * (area / (perimeter ** 2)) # 结合面积和圆度筛选 if 50 < area < 500 and circularity > 0.5: cv2.drawContours(img_contours, contours, i, (255), thickness=cv2.FILLED) - 形态学操作优化掩码
用开运算消除小噪声点,闭运算填补细胞核内部空洞:# 定义椭圆形结构元素(适配细胞核形状) kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) # 开运算:先腐蚀后膨胀,去除小噪声 img_contours = cv2.morphologyEx(img_contours, cv2.MORPH_OPEN, kernel) # 闭运算:先膨胀后腐蚀,填补内部空洞 img_contours = cv2.morphologyEx(img_contours, cv2.MORPH_CLOSE, kernel)
四、替代方案:Otsu自动阈值分割
如果K-means效果不佳,可尝试Otsu阈值分割(适配细胞核灰度双峰分布的特性):
# 预处理后直接用Otsu阈值生成掩码 _, nuclei = cv2.threshold(cl_img_l, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 后续再进行形态学操作和轮廓筛选
内容的提问来源于stack exchange,提问作者AnxoDoTea
相关产品推荐
相关产品推荐

