Python 如何在没有深入学习的情况下改进肺部分割

Python 如何在没有深入学习的情况下改进肺部分割,python,image-processing,image-segmentation,scikit-image,medical,Python,Image Processing,Image Segmentation,Scikit Image,Medical,我的目标是使用快速常规方法从肺部3D CT扫描中获得每个体素沿切片轴的肺ROI逻辑OR 我尝试过使用不同的方法,如阈值和形态学和分水岭, 但是结果并不像你在下面的图片中看到的那样完美 我将每个体素的整个遮罩的逻辑OR与操作的结果输出进行比较,并根据切片轴的体素标准偏差提取ROI 我的问题是: 在逻辑OR之后,如何使结果看起来非常接近遮罩 使用的数据集(图像和遮罩)为 在下面的代码中,尝试将阈值和形态学结合起来,但问题是: # import necessary libraries import o

我的目标是使用快速常规方法从肺部3D CT扫描中获得每个体素沿切片轴的肺ROI逻辑OR

我尝试过使用不同的方法,如阈值和形态学和分水岭, 但是结果并不像你在下面的图片中看到的那样完美

我将每个体素的整个遮罩的逻辑OR与操作的结果输出进行比较,并根据切片轴的体素标准偏差提取ROI

我的问题是: 在逻辑OR之后,如何使结果看起来非常接近遮罩

使用的数据集(图像和遮罩)为

在下面的代码中,尝试将阈值和形态学结合起来,但问题是:

# import necessary libraries
import os
import numpy as np
import matplotlib.pyplot as plt 
# plt.switch_backend('Qt5Agg')
import glob
import nibabel as nib
from skimage.io import imsave
from skimage.filters import threshold_otsu
from skimage.transform import resize
import skimage.morphology as morph
from skimage import measure, exposure , segmentation
from scipy import ndimage
#---------------------------------------------------------------
# Images
path = 'Nifti_DataSet/COVID-19-CT-Seg_20cases'
Dataset = glob.glob( os.path.join(path, '*.gz') )
# Masks
masks_path = 'Nifti_DataSet/Lung_and_Infection_Mask'
masks_Dataset = glob.glob( os.path.join(masks_path, '*.gz') )
#---------------------------------------------------------------
# Source: https://www.kaggle.com/threedb/improved-lung-segmentation-using-watershed
#---------------------------------------------------------------
def generate_markers(image,thr):
    #Creation of the internal Marker
    marker_internal = (image < thr*image.max()).reshape(image.shape)
    marker_internal
    marker_internal = segmentation.clear_border(marker_internal)
    marker_internal_labels = measure.label(marker_internal)
    areas = [r.area for r in measure.regionprops(marker_internal_labels)]
    areas.sort()
    if len(areas) > 2:
        for region in measure.regionprops(marker_internal_labels):
            if region.area < areas[-2]:
                for coordinates in region.coords:                
                       marker_internal_labels[coordinates[0], coordinates[1]] = 0
    marker_internal = marker_internal_labels > 0
    #Creation of the external Marker
    external_a = ndimage.binary_dilation(marker_internal, iterations=10)
    external_b = ndimage.binary_dilation(marker_internal, iterations=55)
    marker_external = external_b ^ external_a
    #Creation of the Watershed Marker matrix
    marker_watershed = np.zeros((512, 512), dtype=np.int)
    marker_watershed += marker_internal * 255
    marker_watershed += marker_external * 128

    return marker_internal, marker_external, marker_watershed
#================================================================================        
def get_best_th(image):
    seg = np.zeros_like(image)
    for th in range(10):
        th = th/10
        m_internal,m_external, _ = generate_markers(image,th)
        if( (np.sum(m_external) > np.sum(m_internal)) and (np.sum(m_internal) > np.sum(seg))):
            seg = m_internal
            #print(th)
    return seg
#=====================================
def generate_watershed_segmentation(img):
    img2 = exposure.equalize_hist(img)
    segm = get_best_th(img2)
    segm = np.array(segm)
    segm = np.clip(segm,0,255)
    return segm
#===============================================================
# 
# Set a Counter 
ctr = 1
#---------------------------------------------------------------
for image in Dataset:
    # Load the images as nd-arrays
    images = nib.load(image).get_fdata()
    # Resize the images
    masks = resize(images, (256,256))
    # Load the masks as nd-arrays
    masks  = nib.load(os.path.join(masks_path,os.path.basename(image))).get_fdata() 
    # Resize the masks
    masks = resize(masks, (256,256))
    # make logical or for all the masks along slices axis
    masks = masks.any(axis=2)
    # print(masks.shape)
    # Take the Std Deviation for all the images along slices axis
    std = np.std(images, axis=2)
    stdcp = std.copy()
    # suppress the low values
    std[std < 0.1 * np.max(std)] = 0.0
    # Normalize The Output
    image = 1. * std / np.max(std)
    # Threshold the result
    val = threshold_otsu(image-std)
    image2 = (image-std) < val
    # Threshold again after masking with the previous result
    val2 = threshold_otsu(image2*image*(image-std))
    result = (image2*image*(image-std)) < val2
    #-------------------------------------------
    #           Morphology Part
    #===========================================
    # Structuring Element
    radius = 5
    # SE = morph.disk(radius)
    SE = morph.star(radius)
    # SE = morph.diamond(radius)
    #-------------------------------------------
    #        Morphological Operations
    #-------------------------------------------
    res2 = morph.binary_erosion(result,selem=SE)
    res2 = morph.remove_small_objects(res2)
    # res2 = morph.binary_opening(res2,selem=SE)
    res2 = morph.label(res2)
    #---------Largest Connected Component--------------------
    lab = np.argmax(np.unique(res2,return_counts=True)[1][1:])
    lab +=1
    res2[res2!=lab] = 0
    res2 = res2.astype(np.uint8)
    # ----More Morphological operations---------
    res2 = morph.remove_small_holes(res2)
    #-------------------------------------------
    res3 = generate_watershed_segmentation(stdcp)
    #-------------------------------------------
    #        Visualize the Results
    #-------------------------------------------
    plt.figure(num='image_%d'%ctr)

    plt.subplot('221')
    plt.imshow(masks)
    plt.title('masks after Logical OR')
    plt.axis('off')
    plt.subplot('222')
    plt.imshow(result)
    plt.title('after first stage')
    plt.axis('off')
    plt.subplot('223')
    plt.imshow(res2)
    plt.title('Result')
    plt.axis('off')   
    plt.subplot('224')
    plt.imshow(res3)
    plt.title('watershed')
    plt.axis('off')  
    # figManager = plt.get_current_fig_manager()
    # figManager.window.showMaximized()
    plt.show()
    #-----------------
    # Increase the counter
    ctr+=1
#导入必要的库
导入操作系统
将numpy作为np导入
将matplotlib.pyplot作为plt导入
#plt.switch_后端(“Qt5Agg”)
导入glob
将nibabel作为nib导入
从skimage.io导入imsave
从skimage.filters导入阈值\u otsu
从skimage.transform导入调整大小
将skimage.形态学导入为变形
从撇渣进口衡量、风险敞口、细分
从scipy导入ndimage
#---------------------------------------------------------------
#图像
路径='Nifti_数据集/COVID-19-CT-Seg_20例'
Dataset=glob.glob(os.path.join(path,*.gz'))
#面具
掩码\u路径='Nifti\u数据集/肺部\u和感染\u掩码'
masks_Dataset=glob.glob(os.path.join(masks_path,*.gz'))
#---------------------------------------------------------------
#资料来源:https://www.kaggle.com/threedb/improved-lung-segmentation-using-watershed
#---------------------------------------------------------------
def生成_标记(图像,thr):
#创建内部标记
marker_internal=(image2:
对于测量中的区域。区域属性(标记\u内部\u标签):
如果region.area<区域[-2]:
对于region.coords中的坐标:
标记\u内部\u标签[坐标[0],坐标[1]]=0
标记\u内部=标记\u内部\u标签>0
#创建外部标记
外部\u a=nImage.二进制\u膨胀(标记\u内部,迭代次数=10)
外部\u b=nImage.二进制\u膨胀(标记\u内部,迭代次数=55)
标记器\u外部=外部\u b^外部\u a
#流域标记矩阵的创建
marker_流域=np.zeros((512,512),dtype=np.int)
标记_流域+=标记_内部*255
标记_分水岭+=标记_外部*128
返回标记\内部、标记\外部、标记\分水岭
#================================================================================        
def get_best_th(图像):
seg=np.类零(图)
对于范围(10)内的th:
th=th/10
m_内部,m_外部,u=生成标记(图像,th)
如果((np.sum(m_外部)>np.sum(m_内部))和(np.sum(m_内部)>np.sum(seg)):
seg=m_内部
#印刷品(th)
返回段
#=====================================
def生成流域分割(img):
img2=曝光。均衡历史(img)
segm=获得最佳值(img2)
segm=np.数组(segm)
segm=np.夹子(segm,0255)
返回segm
#===============================================================
# 
#设置计数器
ctr=1
#---------------------------------------------------------------
对于数据集中的图像:
#将图像作为nd数组加载
images=nib.load(image.get_fdata()
#调整图像大小
遮罩=调整大小(图像,(256256))
#将掩码加载为nd数组
masks=nib.load(os.path.join(masks\u path,os.path.basename(image))).get\u fdata()
#调整遮罩的大小
遮罩=调整大小(遮罩,(256256))
#为沿轴的所有遮罩设置逻辑或
遮罩=遮罩。任意(轴=2)
#打印(遮罩.形状)
#取沿切片轴的所有图像的标准偏差
标准=np.std(图像,轴=2)
stdcp=标准副本()
#抑制低值
标准[标准<0.1*np.最大值(标准)]=0.0
#规范化输出
图像=1。*标准/净功率最大值(标准)
#阈值结果
val=阈值_大津(图像标准)
图像2=(图像标准)