You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

细胞核分割程序中背景噪声残留问题的优化咨询

细胞核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)

优化方案

一、预处理阶段优化

  1. 切换至更适配的颜色通道
    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)
    
  2. 添加去噪步骤
    在CLAHE增强后加入高斯/中值滤波,消除背景颗粒噪声:
    # CLAHE后添加高斯模糊去噪
    cl_img_l = cv2.GaussianBlur(cl_img_l, (3,3), 0)
    # 或中值滤波(更适合去除椒盐噪声)
    # cl_img_l = cv2.medianBlur(cl_img_l, 3)
    

二、K-means分割阶段优化

  1. 使用多通道特征聚类
    单通道灰度信息不足以区分细胞核、细胞质和基质,建议结合多通道特征(如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))
    
  2. 调整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)
    

三、后处理阶段优化

  1. 修复轮廓筛选逻辑
    当前代码中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)
    
  2. 形态学操作优化掩码
    用开运算消除小噪声点,闭运算填补细胞核内部空洞:
    # 定义椭圆形结构元素(适配细胞核形状)
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:40:35