完整的论文代码见文章末尾 以下为核心内容
摘要
在医学图像处理领域,肺部图像的分割是一个重要的研究方向,特别是针对肺部疾病的检测与诊断。传统的X射线和CT(计算机断层扫描)是常用的肺部成像技术,但MRI(磁共振成像)由于其对软组织成像的优越性,正逐渐在肺部成像中得到更多的应用。与CT图像相比,MRI图像可以提供更高的对比度和细节,尤其在软组织和病变检测方面表现出色。然而,MRI图像的肺部分割也面临诸多挑战,需要先进的图像处理技术来实现准确的分割。
训练过程
本项目将使用公开的肺部 MRI 图像数据集,该数据集包含多种肺部疾病的 MRI 图 像,并附有专家标注的肺部区域掩码。数据集包含多个患者的多时相图像,涵盖不同的 病理情况和成像条件,能够为算法的训练和评估提供丰富的样本。
模型搭建
import torch
from torch import nn
import torch.nn.functional as F
class DoubleConv(nn.Module):
def __init__(self, in_channels, out_channels, mid_channels=None):
super().__init__()
if not mid_channels:
mid_channels = out_channels
self.double_conv = nn.Sequential(
nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1),
nn.BatchNorm2d(mid_channels),
nn.ReLU(inplace=True),
nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)
)
def forward(self, x):
return self.double_conv(x)
class ResBlock(nn.Module):
def __init__(self, in_channels, out_channels):
super(ResBlock, self).__init__()
self.downsample = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(out_channels))
self.double_conv = DoubleConv(in_channels, out_channels)
self.down_sample = nn.MaxPool2d(2)
self.relu = nn.ReLU()
def forward(self, x):
identity = self.downsample(x)
out = self.double_conv(x)
out = self.relu(out + identity)
return self.down_sample(out), out
class UpBlock(nn.Module):
def __init__(self, in_channels, out_channels):
super(UpBlock, self).__init__()
self.up_sample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
self.double_conv = DoubleConv(in_channels, out_channels)
def forward(self, down_input, skip_input):
x = self.up_sample(down_input)
# input is CHW
diffY = skip_input.size()[2] - x.size()[2]
diffX = skip_input.size()[3] - x.size()[3]
x = F.pad(x, [diffX // 2, diffX - diffX // 2,
diffY // 2, diffY - diffY // 2])
x = torch.cat([x, skip_input], dim=1)
return self.double_conv(x)
class OutConv(nn.Module):
def __init__(self, in_channels, out_channels):
super(OutConv, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)
def forward(self, x):
return self.conv(x)
class ResUNet(nn.Module):
def __init__(self, out_classes=2):
super(ResUNet, self).__init__()
self.down_conv1 = ResBlock(3, 64)
self.down_conv2 = ResBlock(64, 128)
self.down_conv3 = ResBlock(128, 256)
self.down_conv4 = ResBlock(256, 512)
self.double_conv = DoubleConv(512, 1024)
self.up_conv4 = UpBlock(512 + 1024, 512)
self.up_conv3 = UpBlock(256 + 512, 256)
self.up_conv2 = UpBlock(128 + 256, 128)
self.up_conv1 = UpBlock(128 + 64, 64)
self.conv_last = nn.Conv2d(64, out_classes, kernel_size=1)
def forward(self, x):
x, skip1_out = self.down_conv1(x)
x, skip2_out = self.down_conv2(x)
x, skip3_out = self.down_conv3(x)
x, skip4_out = self.down_conv4(x)
x = self.double_conv(x)
x = self.up_conv4(x, skip4_out)
x = self.up_conv3(x, skip3_out)
x = self.up_conv2(x, skip2_out)
x = self.up_conv1(x, skip1_out)
x = self.conv_last(x)
return x
使用UNet模型,使用 SGD 优化器,学习率为 1e-3,动量为 0.9。使用 CosineAnnealingLR 学习率调度器。损失函数使用 DiceCELoss。每个批次包含 16 个样本,共训练500个批次。
评价指标
本文输出分割图大小为388x388,使用测试集计算分割为肺部和背景的平均像素点数量评估模型性能。
再使用LOU 指标来评估模型效果,LOU(Localization Overlap Union) 是一个衡量图像分割和目标检测中预测结果与实际标注之间重叠程度的指标。
IoU = 0:表示预测结果与实际标注完全不重叠。
0 < IoU < 0.5:表示预测结果与实际标注有部分重叠,但重叠程度较低。
0.5 ≤ IoU < 1:表示预测结果与实际标注有较高程度的重叠,越接近1,说明预测结果越准确。
IoU = 1:表示预测结果与实际标注完全重叠,预测结果非常准确。
• 真阳性 (TP):有 8362 个像素被正确识别为肺部,这表明模型在检测肺部区域方面表现良好。
• 假阳性 (FP):有 1544 个像素被错误识别为肺部,这些像素实际上属于背景但被错误预测为肺部。相比于真阳性,这个数字相对较小。
• 假阴性 (FN):有 957 个实际属于肺部的像素被错误预测为背景。这表明模型漏掉了一些肺部区域。
实验结果
真实对应的肺部如下,图中共有八个子图,每个子图显示了一对被分割出来的肺部轮廓。背景是黑色的,肺部区域是白色的。
Unet网络在图像分割中表现出色,尤其在保持边界清晰度方面。对比图像可以看出,Unet网络分割出的肺部边界较为平滑,细节保留较好。这是由于Unet网络结构中对称的下采样和上采样路径,可以有效捕捉到图像的全局和局部信息。
从对比图像中可以看出,Unet网络分割出的肺部区域较为完整,缺失区域较少。这是因为Unet在上采样阶段通过跳跃连接(skip connections)结合了高分辨率特征,增强了分割结果的准确性和完整性。
Unet网络对于MRI图像中的噪声有较好的鲁棒性。在对比图像中,背景噪声较少,伪影较少,显示出Unet网络在处理复杂医学图像时的优越性能。
Unet网络分割结果在对称性方面表现出色。对比图像中,左右肺部的分隔线一致,显示出Unet网络在捕捉对称结构方面的能力。这对于医学图像中的解剖结构分割尤为重要。
获取方式
点这里论文 代码 ipynb文件都有 无需运行