LUNA 2016 数据集详解
LUNA16数据集的由来
LUNA 2016 数据集来自2016年LUng Nodule Analysis比赛,这里是其官方网站。
LUNA16数据集是最大公用肺结节数据集LIDC-IDRI的子集,LIDC-IDRI它包括1018个低剂量的肺部CT影像。LIDC-IDRI删除了切片厚度大于3mm和肺结节小于3mm的CT影像,剩下的就是LUNA16数据集了。
其数据集的文件内容如下:
mdh数据格式详解
这里有一篇很好的文章,关于医疗影像的mhd和dcm格式图像的读取和坐标转换
每个病例的数据的存储都是由一个.mhd和一个.raw格式的文件组成。.mdh是说明文件,具体数据在.raw文件中,
mdh样例:
ObjectType = Image
NDims = 3 #三维数据
BinaryData = True #二进制数据
BinaryDataByteOrderMSB = False
CompressedData = False
TransformMatrix = 1 0 0 0 1 0 0 0 1 #100,010,001 分别代表x,y,z
Offset = -195 -195 -378 #原点坐标
CenterOfRotation = 0 0 0
AnatomicalOrientation = RAI
ElementSpacing = 0.7617189884185791 0.7617189884185791 2.5 #像素间隔 x,y,z
DimSize = 512 512 141 #数据的大小 x,y,z
ElementType = MET_SHORT
ElementDataFile = 1.3.6.1.4.1.14519.5.2.1.6279.6001.173106154739244262091404659845.raw #数据存储的文件名
python读取mdh的方法
mhd已经交代了图像数据的信息,接下来对图像数据进行读取,这里主要用的Python中的SimpleITK库
import SimpleITK as sitk
import matplotlib.pyplot as plt
case_path = './1.3.6.1.4.1.14519.5.2.1.6279.6001.126264578931778258890371755354.mhd'
itkimage = sitk.ReadImage(case_path) #这部分给出了关于图像的信息,可以打印处理查看,这里就不在显示了
#print(itkimage)
image = sitk.GetArrayFromImage(itkimage) #z,y,x
#查看第100张图像
plt.figure()
plt.imshow(image[100,:,:])
annotations.csv坐标转换
annotations.csv中提供了医生标注肺结节位置信息
seriesuid:表示每个病例图像对应的文件名
coordX,coordX,coordX,diameter_mm:表示医生标注的结节位置信息和直径
在使coordX用卷积网络对肺结节进行检测时,我们需要根据医生提供的标注信息,在图像中找到相应的肺结节位置,接下来说医生标注的坐标与图像中的坐标的关系。
mhd中给定了图像中的原点坐标为(-195 ,-195 ,-378) #x,y,z
像素间隔为(0.7617189884185791,0.7617189884185791,2.5) #x,y,z
通过以上信息可以计算结节相对原点的坐标,然后用这个坐标除以像素间隔,即为在图像中对应的结节位置
#世界坐标转换到图像中的坐标
def worldToVoxelCoord(worldCoord, origin, spacing):
stretchedVoxelCoord = np.absolute(worldCoord - origin)
voxelCoord = stretchedVoxelCoord / spacing
return voxelCoord
#图像上的坐标转换为世界坐标
def VoxelToWorldCoord(voxelCoord, origin, spacing):
strechedVocelCoord = voxelCoord * spacing
worldCoord = strechedVocelCoord + origin
return worldCoord
LUNA16数据集肺结节显示
LUNA16数据集肺结节显示代码如下:
import SimpleITK as sitk
import matplotlib.pyplot as plt
import numpy as np
filename='data\\1.3.6.1.4.1.14519.5.2.1.6279.6001.173106154739244262091404659845.mhd'
itkimage = sitk.ReadImage(filename)#读取.mhd文件
OR=itkimage.GetOrigin()
print(OR)
SP=itkimage.GetSpacing()
print(SP)
numpyImage = sitk.GetArrayFromImage(itkimage)#获取数据,自动从同名的.raw文件读取
def show_nodules(ct_scan, nodules,Origin,Spacing,radius=20, pad=2, max_show_num=4): # radius是正方形边长一半,pad是边的宽度,max_show_num最大展示数
show_index = []
for idx in range(nodules.shape[0]): # lable是一个nx4维的数组,n是肺结节数目,4代表x,y,z,以及直径
if idx < max_show_num:
if abs(nodules[idx, 0]) + abs(nodules[idx, 1]) + abs(nodules[idx, 2]) + abs(nodules[idx, 3]) == 0:
continue
x, y, z = int((nodules[idx, 0]-Origin[0])/SP[0]), int((nodules[idx, 1]-Origin[1])/SP[1]), int((nodules[idx, 2]-Origin[2])/SP[2])
print(x, y, z)
data = ct_scan[z]
radius=int(nodules[idx, 3]/SP[0]/2)
#pad = 2*radius
# 注意 y代表纵轴,x代表横轴
data[max(0, y - radius):min(data.shape[0], y + radius),
max(0, x - radius - pad):max(0, x - radius)] = 3000 # 竖线
data[max(0, y - radius):min(data.shape[0], y + radius),
min(data.shape[1], x + radius):min(data.shape[1], x + radius + pad)] = 3000 # 竖线
data[max(0, y - radius - pad):max(0, y - radius),
max(0, x - radius):min(data.shape[1], x + radius)] = 3000 # 横线
data[min(data.shape[0], y + radius):min(data.shape[0], y + radius + pad),
max(0, x - radius):min(data.shape[1], x + radius)] = 3000 # 横线
if z in show_index: # 检查是否有结节在同一张切片,如果有,只显示一张
continue
show_index.append(z)
plt.figure(idx)
plt.imshow(data, cmap='gray')
plt.show()
b = np.array([[-116.2874457,21.16102581,-124.619925,10.88839157],[-111.1930507,-1.264504521,-138.6984478,17.39699158],[73.77454834,37.27831567,-118.3077904,8.648347161]])
show_nodules(numpyImage,b,OR,SP)