You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python实现含肿瘤脑部MRI图像颅骨去除与肿瘤分割技术问询

嘿,我来帮你搞定这个脑部MRI处理的问题!你提到的颅骨去除(移除最大轮廓)和后续的肿瘤分割,用Python结合OpenCV、NumPy就能实现,我会结合你给出的代码片段一步步完善,给你清晰的实现思路。

第一步:颅骨去除——正确处理最大轮廓

你之前尝试提取轮廓但不知道怎么移除最大轮廓,核心思路是:在脑部MRI中,颅骨通常是面积最大的轮廓(因为它包围整个脑部区域),我们可以通过识别这个最大轮廓,生成掩码来屏蔽它,从而得到仅保留脑部的图像。

完善你的get_brain函数

先补全你未写完的代码,这里我们用OpenCV来处理轮廓,步骤如下:

  1. 先完成你已经在做的图像归一化(Z-score归一化),增强后续阈值处理的稳定性;
  2. 将归一化后的图像转换为8位无符号整数(OpenCV的轮廓处理需要这种格式);
  3. 用Otsu自动阈值法生成二值图像,区分前景(脑部)和背景(颅骨/其他);
  4. 提取所有外部轮廓,找到面积最大的那个(就是颅骨的轮廓);
  5. 创建掩码,将最大轮廓(颅骨)区域屏蔽,保留内部的脑部区域;
  6. 将掩码与原图像结合,得到无颅骨的脑部图像。

代码如下:

import numpy as np
import cv2

def get_brain(img):
    # 1. Z-score归一化(你已有的步骤)
    mean = np.mean(img)
    std = np.std(img)
    img_normalized = (img - mean) / std
    
    # 2. 转换为8位无符号整数(OpenCV处理需要)
    img_normalized = cv2.normalize(img_normalized, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
    
    # 3. Otsu自动二值化,区分脑部和背景
    _, binary_img = cv2.threshold(img_normalized, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    # 这里用THRESH_BINARY_INV是因为通常MRI中颅骨信号低,二值化后背景是白色,需要反转让脑部为白色
    
    # 4. 提取外部轮廓,找到最大的那个(颅骨轮廓)
    contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    max_area = -1
    max_contour = None
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area > max_area:
            max_area = area
            max_contour = cnt
    
    # 5. 创建掩码:屏蔽最大轮廓(颅骨),保留内部脑部
    mask = np.zeros_like(img_normalized)
    # 填充最大轮廓内部为白色(255),这样后续与原图像结合时保留脑部
    cv2.drawContours(mask, [max_contour], 0, 255, thickness=cv2.FILLED)
    # 这里如果发现屏蔽的是脑部而非颅骨,可以把mask取反:mask = 255 - mask
    
    # 6. 应用掩码得到无颅骨的脑部图像
    brain_img = cv2.bitwise_and(img_normalized, mask)
    
    return brain_img

关键细节说明

  • 关于二值化的THRESH_BINARY_INV:如果你的MRI图像中脑部信号是高亮的,可能不需要反转,直接用THRESH_BINARY即可。可以根据自己的图像调整,看二值化后的结果是否正确区分了脑部和颅骨。
  • 如果最大轮廓不是颅骨:可以检查轮廓的面积排序,有时候可能需要排除面积过大的轮廓(比如整个图像的边框),或者取第二大的轮廓,这取决于你的图像格式。
第二步:肿瘤分割

得到无颅骨的脑部图像后,分割肿瘤可以分两种情况:

方法1:传统图像处理(适合肿瘤信号差异明显的情况)

肿瘤在MRI(比如T2加权像)中通常信号较高,可以用阈值法提取:

def segment_tumor(brain_img):
    # 用Otsu阈值法分割肿瘤(假设肿瘤信号高于正常脑部)
    _, tumor_mask = cv2.threshold(brain_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    # 可以用形态学操作去除噪声:比如开运算
    kernel = np.ones((3,3), np.uint8)
    tumor_mask = cv2.morphologyEx(tumor_mask, cv2.MORPH_OPEN, kernel)
    # 将掩码应用到脑部图像,得到肿瘤区域
    tumor_img = cv2.bitwise_and(brain_img, tumor_mask)
    return tumor_img, tumor_mask

方法2:深度学习模型(适合复杂情况)

如果肿瘤边界模糊、信号差异小,传统方法效果不好,可以用U-Net这类专门的医学图像分割模型。你可以用PyTorch或TensorFlow实现,训练自己的模型(需要标注好的数据集),或者用预训练模型直接推理。

完整使用示例
# 读取MRI图像(假设是单通道灰度图)
img = cv2.imread('brain_mri.png', cv2.IMREAD_GRAYSCALE)
# 去除颅骨
brain_img = get_brain(img)
# 分割肿瘤
tumor_img, tumor_mask = segment_tumor(brain_img)

# 可视化结果
import matplotlib.pyplot as plt
plt.figure(figsize=(12,4))
plt.subplot(131), plt.imshow(img, cmap='gray'), plt.title('Original MRI')
plt.subplot(132), plt.imshow(brain_img, cmap='gray'), plt.title('Brain (No Skull)')
plt.subplot(133), plt.imshow(tumor_img, cmap='gray'), plt.title('Segmented Tumor')
plt.show()

内容的提问来源于stack exchange,提问作者Erko

火山引擎 最新活动