欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

resnet18病理图像二分类

程序员文章站 2022-07-04 22:59:07
...

简介

简单的数字病理图像分类。首先将分为三个数据集,训练集,验证集,和测试集。这三个数据集由同一种类不同的图片切割组合。训练集由两个图片切割的小图片组成 ,验证集由另一个该类别的图片切割的小图片组成,测试集由另一个该类别的图片切割的小图片组成。
在训练集中类别1的有24张,类别0的有29张。测试集中包含15张有病的图片,一张没有标记的图片。利用resnet18对这些图片进行二分类。

图片的剪裁

由于病理图像很大,需要对其进行剪裁。病理图像为.svs图片,很大,我们需要借助openslide来处理这些图像。病理图片上有标注,哪些是患病区域,同时每个.svs对应的都有一个.xml标注文件。首先将.xml文件生成.svs对应的掩膜图像。将对应标注有病的区域为白色,其他没有标注的区域为黑色,将掩膜和.svs对应起来,在切割的过程中,如果掩膜对应区域的白色像素个数的总和大于要切割面积的一半,就切割.svs对应的区域,保存切割下来的图片在train/1文件夹下。如果白色区域的面积过小,则丢弃该图片。对于黑色区域,我们要区分该区域是有图像还是空白的,判断依据是根据.svs对应区域的像素值来判断。
图片切割大小的选择:原始的.svs图片很大,且大多数.svs上的标注有的是小的连通区域,有的是大的连通区域,而且图片中的空白区域也较多。因此,将切割图片的大小设置为2000,3000,4500.对比切割之后的效果发现,4500大小的结果最好,切割的标记不是那么的边边角角,2000,3000,太小。

切割有病区域的图片:

    for i in range(len(names)):
        #paths=os.path.join('./Image/1/svs/', names[i] + '.svs')
        na=names[i]
        slide = openslide.OpenSlide(os.path.join('./Image/1/svs/', names[i] + '.svs'))
        IM_ROWS = slide.dimensions[1]  # 对应图像的高
        IM_COLS = slide.dimensions[0]
        Image.MAX_IMAGE_PIXELS = None
        tumor_mask = np.array(Image.open('./Image/1/mask' + '/' + names[i] + '.png'))
        #image = openslide.OpenSlide(paths)  # 读取svs
        for i in range(0, IM_ROWS - cut_size, spacing):
            for j in range(0, IM_COLS - cut_size, spacing):
                tumor_mask_np = tumor_mask[i:i + cut_size, j:j + cut_size]

                if (tumor_mask_np == 255).sum() >= area:
                    save_name = '{}_{}_{}_{}.png'.format(na, i, j, cut_size)#剪裁图片命名字

                    #image=image[j:j+cut_size,i:i+cut_size]#剪裁对应位置的图片
                    save_path2=os.path.join(save_path,save_name)#剪裁有病图片的存储路径
                    #cv2.imwrite(save_name,image)
                    try:
                        img = np.array(slide.read_region((j, i), 0, (cut_size, cut_size)), dtype=np.uint8)[..., 0:3]
                    except:
                        slide.close()
                        slide = openslide.OpenSlide('./Image/1/svs' + '/' + names[i] + '.svs')
                        continue
                    Image.fromarray(img).save(save_path2)

在剪裁图片的过程中要将 Image.MAX_IMAGE_PIXELS 的值设置为None,否则的话会报超出范围的错误,带不开图片。

使用Resnet18进行二分类

使用迁移学习:

model=models.resnet18(pretrained=True)
for para in model.parameters():
    para.require_grad=False
model.fc=nn.Linear(512,2)

数据预处理:
只进行了简单的数据预处理

normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
transform = transforms.Compose([
    transforms.Resize(size=(227, 227)),
    transforms.RandomRotation(20),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    normalize
])

由于图片数量较少,所以batch_size也设置的相对较少,batch_size=4,epoch=100.
利用迁移学习,将已经训练好的resnet18迁移过来,改变最后一层全连接层的输出。损失函数使用的是CrossEntropyLoss,optimizer使用的是Adam,,learning rate 是0.01.
训练的结果:发现当epoch为55左右的时候准确率很高了
resnet18病理图像二分类
验证集和测试集的结果
resnet18病理图像二分类

使用Vgg网络进行分类

训练的结果:当epoch为100时训练效果仍然不好,loss仍然很大,爱acc也不高,调整learning rate为0.001.效果仍然不好,所以增大epoch,改变optimizer为SGD,修改learning rate继续训练。

验证和测试的结果:
resnet18病理图像二分类
从测试的结果来看,resnet的效果较好。

相关标签: 深度学习