使用imwrite将.nii转.tif时掩码存为黑图的问题咨询
问题解决:NII转TIF标签全黑 + 直接用NII喂U-Net的方案
一、标签转TIF全黑的原因及修复
核心原因
你标签里的数值大概率是0(背景)、1、2这类小整数,直接转成int8保存的话,这些值在8位图像的0-255动态范围里占比极低,肉眼看起来就是黑色。比如值为1的像素,亮度仅为1/255,几乎和背景0没区别。另外你的代码还有几个小问题没处理:
- 缺少
Path和re的导入,运行会报错 - 重复导入了
nibabel和numpy,没必要 imageio保存单通道标签的兼容性不如tifffile
修复后的代码
import nibabel as nib import numpy as np import glob from pathlib import Path import re from tifffile import imsave # 遍历所有标签文件 for filepath in glob.iglob('data/Task04_Hippocampus/labelsTr/*.nii.gz'): # 加载nii数据 label_data = nib.load(filepath).get_fdata() # 将标签值映射到0-255范围(根据你的标签类别数调整,比如类别是0、1、2,乘以127即可) # 确保转换为uint8,这是tif图像常用的无符号8位格式 label_data = (label_data * 127).astype(np.uint8) # 处理文件名 base = Path(filepath).stem base = re.sub('.nii', '', base) # 遍历所有切片 _, _, z = label_data.shape for i in range(z): slice_data = label_data[:, :, i] # 用tifffile的imsave保存,更稳定 save_path = f'data/Task04_Hippocampus/masks/{base}_{i}.tif' imsave(save_path, slice_data)
关键改动说明
- 把标签值乘以127(如果你的标签有3类:0、1、2,1127=127,2127=254,这样在图像里能明显区分)
- 改用
np.uint8类型,避免int8的负数范围干扰 - 用
tifffile.imsave替代imageio.imwrite,对医学标签的支持更友好
二、直接用NII格式喂U-Net的方法
完全没必要转成TIF,直接在PyTorch的Dataset里读取NII文件就行,步骤如下:
1. 自定义Dataset类
import nibabel as nib import numpy as np from torch.utils.data import Dataset class NiiDataset(Dataset): def __init__(self, image_dir, label_dir): self.image_paths = sorted(glob.glob(f'{image_dir}/*.nii.gz')) self.label_paths = sorted(glob.glob(f'{label_dir}/*.nii.gz')) def __len__(self): return len(self.image_paths) def __getitem__(self, idx): # 加载图像和标签 image = nib.load(self.image_paths[idx]).get_fdata().astype(np.float32) label = nib.load(self.label_paths[idx]).get_fdata().astype(np.int64) # 调整维度:U-Net通常需要 (通道数, 深度, 高度, 宽度) 格式(3D U-Net) # 如果是2D U-Net,需要遍历切片,这里以3D为例 image = np.expand_dims(image, axis=0) # 添加通道维度 (1, D, H, W) label = np.expand_dims(label, axis=0) # 转换为tensor import torch image = torch.from_numpy(image) label = torch.from_numpy(label) return image, label
2. 构建Dataloader
from torch.utils.data import DataLoader train_dataset = NiiDataset( image_dir='data/Task04_Hippocampus/imagesTr', label_dir='data/Task04_Hippocampus/labelsTr' ) train_loader = DataLoader(train_dataset, batch_size=2, shuffle=True)
说明
- 如果是2D U-Net训练,只需要在
__getitem__里遍历切片,把每个切片作为一个样本,或者在Dataloader里处理 - 这种方式省去了格式转换的步骤,避免了图像压缩或格式转换带来的信息损失,训练效率更高
内容的提问来源于stack exchange,提问作者AMAS AL
相关产品推荐
相关产品推荐

