深度学习实战肺部医疗图像分割【U-Net模型+肺部CT数据集+PyQt5界面】

在这里插入图片描述

U-Net肺医疗图像分割


研究背景

  随着计算机的发明与硬件技术的不断发展,人们对实际生活和工作中遇到的问题的解决方式也在无形中悄然发生变化,很多过去需要花费巨大人力和财力才能完成的任务,现在可以直接交给软件来实现。机器学习和计算机视觉就是这些技术中非常重要的研究热点和研究方向。

  目前肺部疾病的诊断的主要治疗方式有手术治疗、介入治疗、中药治疗等方式,其中肺切除手术和肝移植手术仍是目前最有效的根治方式"。而在进行手术之前,外科医生通常需要先获取肺相关的解剖信息和定量信息,比如肺的位置结构信息以及体积信息等。随着医学诊疗科技的不断发展与进步,日前可以通过医学影像技术来获取这些信息。

  医学影像技术主要包括计算机断层扫描(Computer tomography, CT)、核磁共振成像(Magnetic resonance imaging, MRI)、 放射性核素成像(Radionuclide Imaging, RNI)、超声成像(Ultrasound)、 正电子发射断层扫描( Positron emission tomography, PET)等技术。这些技术已成为现代医学的主要诊疗手段之一,在现代医学的疾病筛查、诊断以及治疗等过程中发挥着重要的作用。其中CT成像技术由于具有密度分辨率高、空间分辨率高以及组织结构影像无重叠等优点,被广泛应用于肺疾病的诊断中。

  在获得腹部的CT图像后,若想进-步获取肺的位置以及体积等信息,则需要先在CT图像中将肺区域标注出来。从腹部的CT图像中精准地分割出肺,是肺疾病诊断、肝功能储备评估以及用于肺3D建模的第一步,也是肺手术前极为重要的-步。在实际应用中,通常需要拥有相关专业知识以及大量实践经验的医生对CT图像进行逐体素的标注,从CT图像中手工分割出肺区域。然而这个过程极其耗费时间和精力,并且由于受到医生经验差别以及主观因素的影响,不同的医生给出的分割结果往往是有差别的B。因此为了减轻医生的工作量,加快分割效率,以及获得更加一致的分割结果,利用当前先进的人工智能技术进行自动化的医学图像分割是具有重大意义的。


觉得不错的小伙伴,感谢点赞、关注加收藏哦!更多干货内容持续更新…

代码下载链接

关注博主的G Z H【小蜜蜂视觉】,回复【图像分割】即可获取下载方式


  若您想获得博文中涉及的实现完整全部程序文件(包括手写数据集、py文件,模型权重文件,调试说明等),代码获取与技术指导,具体见可参考博客与视频,已将所有涉及的文件同时打包到里面,软件安装调试有具体说明,我们有专业的调试技术人员,将远程协助客户调试,具体请看安装调试说明.txt,完整文件截图如下:

在这里插入图片描述

一、效果演示

  本文构建的肺部图像分割采用U-Net模型,PyQt5构建界面交互。
在这里插入图片描述

二、整体流程

  U-Net是一种广泛应用于医学图像分割的深度学习网络,尤其在肺部图像分割中表现出色。以下是U-Net用于肺部图像分割的整体技术流程:

2.1 数据准备

  • 数据收集:获取包含肺部图像的医学影像数据集,例如CT或X光图像。数据集应包括原始影像和相应的标注图(ground truth masks)。
  • 数据预处理
    • 图像归一化:对图像进行归一化处理,将像素值缩放到0到1的范围内。
    • 图像裁剪和调整大小:根据需要裁剪或调整图像大小,以适应U-Net输入层的要求。
    • 数据增强:通过旋转、平移、翻转等方法扩充数据集,以增加模型的鲁棒性。

2.2 模型设计

  • U-Net结构
    • 编码器(下采样路径):一系列卷积层和池化层,用于提取图像特征并逐步降低空间维度。
    • 解码器(上采样路径):一系列反卷积层(或上采样层)和卷积层,用于恢复图像的空间分辨率。
    • 跳跃连接:在编码器和解码器之间建立跳跃连接,将编码器中的特征直接传递到解码器相应层,帮助恢复细节信息。

2.3 模型训练

  • 损失函数
    • 常用的损失函数包括二值交叉熵损失(Binary Cross-Entropy Loss)和Dice损失(Dice Loss),用于衡量预测分割与真实分割之间的差异。
  • 优化器
    • 常用的优化器有Adam、SGD等,用于调整模型的权重以最小化损失函数。
  • 训练过程
    • 分割数据集为训练集和验证集。
    • 进行多轮(epoch)迭代训练,每轮中通过前向传播和反向传播更新模型参数。
    • 在每个epoch结束后评估模型在验证集上的表现,调整超参数以优化模型。

2.4 模型评估

  • 评估指标
    • Dice系数:衡量预测结果与真实结果的重叠程度。
    • 交并比(IoU):衡量预测结果与真实结果的交集与并集的比值。
    • 精准率和召回率:衡量模型的准确性和召回能力。

2.5 模型推理

  • 图像输入:将待分割的肺部图像输入训练好的U-Net模型。
  • 图像分割:模型输出分割结果,即每个像素属于前景(肺部)或背景的概率。
  • 后处理:对模型输出的概率图进行阈值化处理,生成最终的二值分割图。根据需要进行连通域分析等进一步处理,以去除噪声和伪影。

2.6 部署和应用

  • 模型部署:将训练好的模型部署到实际应用环境中,可以是服务器、云端或者嵌入式设备。
  • 实时应用:在实际应用中,实时处理输入的肺部图像,并生成分割结果,用于临床诊断和研究。

三、U-Net图像分割原理

3.1 概述

  U-net是一种图像分割技术,主要用于图像分割任务。这些特点使U-net在医学影像领域具有很高的实用性,并导致广泛采用U-net作为医学成像中分割任务的主要工具。U-net在几乎所有主要的成像方式中都得到了广泛的应用,从CT扫描、MRI到X光检查和显微镜。此外,虽然U-net在很大程度上是一种细分工具,但也有一些例子U-net在其他应用中的使用。鉴于U-net的潜力仍在增长,这部叙事文学综述分析了U-net体系结构的众多发展和突破,并提供了对近期趋势的观察。我们还讨论了在深度学习和讨论这些工具如何促进U-net。

  得益于计算机视觉深度学习的最新进展在过去十年中,深度学习越来越受到重视用于医学图像的分析。而使用计算机视觉的深度学习在中国得到了快速发展在许多不同的领域,它仍然面临着一些挑战医学影像领域。有很多突破多年来克服这些问题的技术挑战,新的研究不断导致开发更新颖和创新的方法。其中U-net是一种在国内广泛采用的深度学习技术医学影像学界。

  U-net是一种主要设计的神经网络结构用于图像分割[1]。U网的基本结构架构由两条路径组成。第一条路是收缩路径,也称为编码器或分析路径,类似于常规卷积网络和提供分类信息。第二个是扩展路径,也称为解码器或合成路径,由上卷积和与收缩路径的特征。这种扩展允许网络学习本地化的分类信息。此外,扩展路径还增加了输出的分辨率,然后可以传递到最终卷积层创建一个完全分割的图像。这个由此产生的网络几乎是对称的,给它一个u形形状大多数人执行的主要规范任务卷积网络是将整个图像分类为单一标签。然而,分类网络无法提供像素级上下文信息,这在医学图像分析中是至关重要的。

3.2 U-Net原理

在这里插入图片描述

  U-Net是一种卷积神经网络(CNN),专门设计用于生物医学图像分割任务。它的结构特点使其能够有效地处理小数据集并产生精确的分割结果。以下是U-Net框架的详细原理说明:

3.2.1 U-Net的基本结构

  U-Net的结构可以分为两个主要部分:编码器(收缩路径)和解码器(扩展路径),中间通过跳跃连接进行特征融合。

编码器(收缩路径)
  • 卷积层:每个卷积层使用小的3x3卷积核进行卷积操作,并且每个卷积操作后跟随一个ReLU激活函数。
  • 池化层:通过2x2最大池化层对特征图进行下采样,减少特征图的尺寸,同时保留重要特征。
  • 多层结构:编码器由多层卷积层和池化层堆叠而成,每下采样一次,特征图的宽度和高度减半,深度加倍。
解码器(扩展路径)
  • 上采样层:通过反卷积(转置卷积)或上采样操作,将特征图尺寸还原,同时恢复空间分辨率。
  • 卷积层:每个上采样层后跟随两个3x3卷积层和ReLU激活函数,逐步细化特征图。
  • 跳跃连接:从编码器的每个层直接连接到解码器相应层,将编码器中提取的高分辨率特征图与解码器中的特征图拼接(concatenate),帮助恢复细节信息。
输出层
  • 最后一个卷积层使用1x1卷积核,减少特征图的深度到目标类数(对于二分类任务,输出一个通道),并应用Sigmoid或Softmax激活函数得到每个像素的分类概率。

3.2.2 工作原理

  U-Net通过多层卷积和池化操作提取图像的多尺度特征,并通过上采样和跳跃连接逐步恢复图像的空间分辨率,从而实现精确的像素级别分类。

编码阶段
  • 输入图像通过一系列卷积和池化操作提取不同尺度的特征。每经过一次池化,图像尺寸减半,特征通道数加倍,从而在不同层次捕捉到图像的不同特征。
  • 编码阶段的最后输出一个低分辨率、高维度的特征图,包含图像的全局上下文信息。
解码阶段
  • 通过上采样操作逐步恢复特征图的原始尺寸。每一次上采样后,通过跳跃连接将编码器相应层的高分辨率特征图拼接到当前特征图中,融合不同尺度的信息。
  • 这种方式不仅能够利用全局上下文信息,还能保留局部细节特征,提升分割精度。

3.2.3 跳跃连接的作用

跳跃连接(skip connections)是U-Net的重要特性之一。它将编码器每一层的特征图直接传递到解码器相应层,避免了信息丢失,并使得模型能够更好地恢复图像细节。具体作用包括:

  • 信息保留:确保细粒度特征在编码过程中不会被完全丢失。
  • 梯度传播:有助于缓解梯度消失问题,使得模型更容易训练。
  • 特征融合:结合不同层次的特征,增强模型对复杂边界和小目标的分割能力。

3.2.4 损失函数和优化

  • 损失函数:U-Net通常使用交叉熵损失函数或Dice系数损失函数,具体选择取决于任务和数据特点。对于二分类任务,常用二值交叉熵;对于多分类任务,使用多类交叉熵。
  • 优化器:常用的优化器包括Adam、SGD等。Adam优化器具有较快的收敛速度和稳定性,因此在U-Net中较为常用。

3.3 U-Net具体实现

3.3.1 编码器

class encoder(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(encoder, self).__init__()
        self.down_conv = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
        )
        # ceil_mode参数取整的时候向上取整,该参数默认为False表示取整的时候向下取整
        self.pool = nn.MaxPool2d(kernel_size=2, ceil_mode=True)

    def forward(self, x):
        out = self.down_conv(x)
        out_pool = self.pool(out)
        return out, out_pool

3.3.2 解码器

class decoder(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(decoder, self).__init__()
        # 反卷积
        self.up = nn.ConvTranspose2d(in_channels, out_channels, kernel_size=2, stride=2)
        self.up_conv = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
        )

    def forward(self, x_copy, x, interpolate=True):
        out = self.up(x)
        if interpolate:
            # 迭代代替填充, 取得更好的结果
            out = F.interpolate(out, size=(x_copy.size(2), x_copy.size(3)),
                                mode="bilinear", align_corners=True
                                )
        else:
            # 如果填充物体积大小不同
            diffY = x_copy.size()[2] - x.size()[2]
            diffX = x_copy.size()[3] - x.size()[3]
            out = F.pad(out, (diffX // 2, diffX - diffX // 2, diffY, diffY - diffY // 2))
        # 连接
        out = torch.cat([x_copy, out], dim=1)
        out_conv = self.up_conv(out)
        return out_conv

3.3.3 U-Net

class BaseModel(nn.Module):
    def __init__(self):
        super(BaseModel, self).__init__()
        self.logger = logging.getLogger(self.__class__.__name__)

    def forward(self):
        raise NotImplementedError

    def summary(self):
        model_parameters = filter(lambda p: p.requires_grad, self.parameters())
        nbr_params = sum([np.prod(p.size()) for p in model_parameters])
        self.logger.info(f'Nbr of trainable parametersL {nbr_params}')

    def __str__(self):
        model_parameters = filter(lambda p: p.requires_grad, self.parameters())
        nbr_params = sum([np.prod(p.size()) for p in model_parameters])
        return super(BaseModel, self).__str__() + f"\nNbr of trainable parameters: {nbr_params}"


class UNet(BaseModel):
    def __init__(self, num_classes, in_channels=1, freeze_bn=False, **_):
        super(UNet, self).__init__()
        self.down1 = encoder(in_channels, 64)
        self.down2 = encoder(64, 128)
        self.down3 = encoder(128, 256)
        self.down4 = encoder(256, 512)
        self.middle_conv = nn.Sequential(
            nn.Conv2d(512, 1024, kernel_size=3, padding=1),
            nn.BatchNorm2d(1024),
            nn.ReLU(inplace=True),
            nn.Conv2d(1024, 1024, kernel_size=3, padding=1),
            nn.ReLU(inplace=True)
        )

        self.up1 = decoder(1024, 512)
        self.up2 = decoder(512, 256)
        self.up3 = decoder(256, 128)
        self.up4 = decoder(128, 64)
        self.final_conv = nn.Conv2d(64, num_classes, kernel_size=1)
        self._initalize_weights()
        if freeze_bn:
            self.freeze_bn()

    def _initalize_weights(self):
        for module in self.modules():
            if isinstance(module, nn.Conv2d) or isinstance(module, nn.Linear):
                nn.init.kaiming_normal_(module.weight)
                if module.bias is not None:
                    module.bias.data.zero_()
            elif isinstance(module, nn.BatchNorm2d):
                module.weight.data.fill_(1)
                module.bias.data.zero_()

    def forward(self, x):
        x1, x = self.down1(x)
        x2, x = self.down2(x)
        x3, x = self.down3(x)
        x4, x = self.down4(x)
        x = self.middle_conv(x)
        x = self.up1(x4, x)
        x = self.up2(x3, x)
        x = self.up3(x2, x)
        x = self.up4(x1, x)
        x = self.final_conv(x)
        return x

    def get_backbone_params(self):
        # There is no backbone for unet, all the parameters are trained from scratch
        return []

    def get_decoder_params(self):
        return self.parameters()

    def freeze_bn(self):
        for module in self.modules():
            if isinstance(module, nn.BatchNorm2d):
                module.eval()

3.4 肺部CT数据集

在这里插入图片描述

3.5 U-Net模型评估

U-Net模型的评估是确保其在图像分割任务中有效性和鲁棒性的重要步骤。评估通常包括定量评估指标的计算和定性结果的分析。以下是详细的U-Net评估流程:

3.5.1 定量评估

在这里插入图片描述

3.5.2 计算评估指标

在模型训练和验证阶段,可以使用这些指标来评估模型性能。在Keras中可以自定义评估函数来计算这些指标:

import numpy as np
from sklearn.metrics import f1_score, jaccard_score

# Example function to calculate Dice coefficient
def dice_coefficient(y_true, y_pred):
    smooth = 1e-6
    y_true_f = np.ravel(y_true)
    y_pred_f = np.ravel(y_pred)
    intersection = np.sum(y_true_f * y_pred_f)
    return (2. * intersection + smooth) / (np.sum(y_true_f) + np.sum(y_pred_f) + smooth)

# Calculate Dice coefficient for validation set
dice_scores = [dice_coefficient(true, pred) for true, pred in zip(val_masks, val_predictions)]
average_dice = np.mean(dice_scores)

# Calculate IoU for validation set
iou_scores = [jaccard_score(true.flatten(), pred.flatten()) for true, pred in zip(val_masks, val_predictions)]
average_iou = np.mean(iou_scores)

# Calculate F1 score for validation set
f1_scores = [f1_score(true.flatten(), pred.flatten()) for true, pred in zip(val_masks, val_predictions)]
average_f1 = np.mean(f1_scores)

print(f'Average Dice Coefficient: {average_dice}')
print(f'Average IoU: {average_iou}')
print(f'Average F1 Score: {average_f1}')

3.6 U-Net分割界面设计

在这里插入图片描述

3.7 U-Net分割预测


def predict(image_file_name):
    
    im = np.asarray(Image.open(image_file_name))
    im = im.reshape((Height, Width, Img_channel))
    im = transform(im).float().cuda()
    im = im.reshape((1,Img_channel,Height,Width))

    output = model(im)
    _, pred = output.max(1)
    pred = pred.view(Height, Width)
    mask_im = pred.cpu().numpy().astype(np.uint8)


    w,h = mask_im.shape
    print(w,h)

    for i in range(0, w):
        for j in range(0, h):
            if mask_im[i, j] == 1:
                # print('xxx')
                mask_im[i,j] = 255

    return mask_im

觉得不错的小伙伴,感谢点赞、关注加收藏哦!更多干货内容持续更新…

代码下载链接

关注博主的G Z H【小蜜蜂视觉】,回复【图像分割】即可获取下载方式

参考文献

[1] 基于改进UNet网络的室内运动目标阴影分割[J]. 刘莹;杨硕.计算机系统应用,2022(12)
[2] 基于SegNet与三维点云聚类的大田杨树苗叶片分割方法[J]. 胡春华;刘炫;计铭杰;李羽江;李萍萍.农业机械学报,2022(06)
[3] 基于DeepLab v3+的葡萄叶片分割算法[J]. 李余康;翟长远;王秀;袁洪波;张玮;赵春江.农机化研究,2022(02)
[4] 基于U-Net的玉米叶部病斑分割算法[J]. 刘永波;胡亮;曹艳;唐江云;雷波.中国农学通报,2021(05)
[5] 针对TT100K交通标志数据集的扩增策略[J]. 龚祎垄;吴勇;陈铭峥.福建电脑,2019(11)
[6] 深度学习自适应学习率算法研究[J]. 蒋文斌;彭晶;叶阁焰.华中科技大学学报(自然科学版),2019(05)
[7] 基于Lab空间和K-Means聚类的叶片分割算法研究[J]. 邹秋霞;杨林楠;彭琳;郑强.农机化研究,2015(09)
[8] 复杂背景下植物叶片的彩色图像分割[J]. 王红君;陈伟;赵辉;岳友军.中国农机化学报,2013(02)
[9] 田间枣树叶片复杂目标图像综合分割方法[J]. 董金勇;王建仑;李道亮;何建磊;王永彬.农业机械学报,2011(01)
[10] 基于Mean-shift和提升小波变换的棉花叶片边缘的图像检测[J]. 李寒;王库;边昊一.农业工程学报,2010(S1)
[11] Image Segmentation Method for Sweetgum Leaf Spots Based on an Improved DeeplabV3+ Network[J]. Cai Maodong;Yi Xiaomei;Wang Guoying;Mo Lufeng;Wu Peng;Mwanza Christine;Kapula Kasanda Ernest.Forests,2022
[12] A MobileNetV2-SENet-based method for identifying fish school feeding behavior[J]. Zhang Lu;Wang Jianping;Li Beibei;Liu Yiran;Zhang Hongxu;Duan Qingling.Aquacultural Engineering,2022
[13] LEMOXINET: Lite ensemble MobileNetV2 and Xception models to predict plant disease[J]. Sutaji Deni;Yıldız Oktay.Ecological Informatics,2022
[14] A bone segmentation method based on Multi-scale features fuse U2Net and improved dice loss in CT image process[J]. Liu Tao;Lu Yonghua;Zhang Yu;Hu Jiahui;Gao Cheng.Biomedical Signal Processing and Control,2022
[15] A Framework Using Binary Cross Entropy - Gradient Boost Hybrid Ensemble Classifier for Imbalanced Data Classification[J]. Isabella S.J.;Srinivasan S.;Suseendran G…Webology,2021
[16] GhostNet: More features from cheap operations[J]. Han K.;Wang Y.;Tian Q.;Guo J.;Xu C.;Xu C…Proceedings of the IEEE Computer Society Conference on Computer Vision and Pattern Recognition,2020
[17] Accuracy and sensitivity of radium mass balances in assessing karstic submarine groundwater discharge in the stratified Calanque of Port-Miou (Mediterranean Sea)[J]. Christelle Claude;;Sabine Cockenpot;;Bruno Arfib;;Samuel Meulé;;Olivier Radakovitch.Journal of Hydrology,2019
[18] ImageNet classification with deep convolutional neural networks[J]. Alex Krizhevsky;;Ilya Sutskever;;Geoffrey E. Hinton.Communications of the ACM,2017
[19] Improving Text Classification Performance Using PCA and Recall-Precision Criteria[J]. M. Zahedi;;A. Ghanbari Sorkhi.Arabian journal for science and engineering,2013
[20] LabelMe: A Database and Web-Based Tool for Image Annotation[J]. Bryan C. Russell;;Antonio Torralba;;Kevin P. Murphy;;William T. Freeman.International Journal of Computer Vision,2008

结束语

由于博主能力有限,本篇文章中提及的方法,也难免会有疏漏之处,希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值