文章目录
- PIL库的图像失真问题
- 使用最小最大值归一化(Min-Max Normalization)预处理
- 消除过暗过亮值
- pytorch中对tensor使用最小最大值归一化处理(torchvision.transforms)
我们在处理CT图像时(以dcm格式为例),在数据预处理方面(主要和PIL.Image相关)会出现图像失真的问题。
我们可以使用最小最大值归一化(Min-Max Normalization)和消除过暗过亮值,来解决相关问题。下面详述。
本文需要用到处理dcm文件的库:pydicom。
本文代码:my GitHub
PIL库的图像失真问题
我们从dcm数据中获取数据矩阵时,直接用 Image.fromarray() 读取时会出现图像失真。
例:
我们先用plt.imshow显示图像没有问题。
用Image读入图像矩阵后,convert过后就出现了问题:
由于图像矩阵传入PIL库后,模式(mode)一般是F(浮点型)或I(整形),无法进一步处理(比如另存为jpg图像格式、在notebook中显示等)。
所以我们一般会使用 convert 方法转换mode,灰度图我们一般转成 “L” 模式。
但是这样会导致图像失真,效果如上图所示。
模式 | 说明 |
---|---|
1 | 1位像素,黑和白,存成8位的像素 |
L | 8位像素,黑白 |
P | 8位像素,使用调色板映射到任何其他模式 |
RGB | 3×8位像素,真彩 |
RGBA | 4×8位像素,真彩+透明通道 |
CMYK | 4×8位像素,颜色隔离 |
YCbCr | 3×8位像素,彩色视频格式 |
I | 32位整型像素 |
F | 32位浮点型像素 |
我们可以将矩阵求和来验证一下是否失真:
以上可以看到 convert(‘L’) 后,图像矩阵的数值已经产生了变化,这也解释了为什么显示出来的图像和plt.imshow()显示的有很大的差别
使用最小最大值归一化(Min-Max Normalization)预处理
我们发现使用convert方法对数值范围的要求在 0~255 之间。而这张图像的矩阵的数值最高达到了2242,所以convert时出现了问题。
最小最大值归一化(Min-Max Normalization)可将矩阵全体数值线性映射到[0, 1]之间。
最后再全体乘以255即可。
我们在传入Image之前对矩阵进行归一化:
max_value = img_array.max()
min_value = img_array.min()
img_array = (img_array - min_value) / (max_value - min_value)
img_array = img_array * 255
具体实现:
以上经过最小最大值归一化,并乘以255后,图像基本就不失真了!
消除过暗过亮值
在实际情况中,不少CT图像的矩阵存在背景数值(CT值)为-2000,并且还会有带极高亮斑的情况。
这种光光做Min-Max Normalization是不够的。
举个例子(观察最大值和最小值):
以上我们发现经过Min-Max Normalization后,图像变得非常暗淡。
我们计算了数据最大值: 9435.0 ,数据最小值: -2000.0
我们查看一下图像矩阵的一行。
可以发现背景的数值是 -2000,并且普通组织区域的数值大约在0~3000左右。
最大值9435应该对应的是图像中的某个亮斑,属于干扰值。
我们可以将图像进行进一步处理,将-2000的部分改成0,大于3000的值改成3000
以上就正常多啦~
pytorch中对tensor使用最小最大值归一化处理(torchvision.transforms)
torchvision.transforms中没有对应最小最大值归一化的方法。
想要在pytorch数据处理中使用最小最大值归一化,可以自己写一个方法放入transoms.Compose中。
消除过暗过亮值 和 最小最大值归一化 处理后的CT图像数据在训练时有助于收敛并提高模型准确率指标。
代码实例:
我们编写一个NormalizeTensor函数即可
from torchvision import transforms
import torch
def NormalizeTensor(data):
minimal = torch.min(data)
return (data - minimal) / (torch.max(data) - minimal)
transform = transforms.Compose([
transforms.Resize((224,224)),
transforms.ToTensor(),
NormalizeTensor,
])
img_open=pydicom.read_file(dcm2)
img_array = img_open.pixel_array
img_array = np.array(img_array, dtype=np.float32)
# 消除过暗过亮值
img_array = np.maximum(img_array, 0) # 消除-2000 CT值
img_array = np.minimum(img_array, 3000) # 消除极亮值
img_array_pil = Image.fromarray(img_array)
img = img_array_pil.convert('L')
img_tensor = transform(img)