资讯详情

CT图像预处理之窗宽窗位调整

1 CT图像的Hu值变换

2 CT调整图像窗宽窗位

1 CT图像的Hu值变换

属于医学领域的概念,通常域的概念(hounsfield unit,HU),它反映了组织对X射线的吸收。黑影表示低吸收区,即低密度区,如肺部含气较多;影子表示高吸收区,即高密度区,如骨骼。但是CT 与X线图像相比,CT密度分辨率高,即密度分辨率高(density resolution)。因此,人体软组织的密度差异很小。虽然吸收系数大多接近水,但也可以形成对比和成像。解剖成像。

计算机领域的概念是指单个像素点的亮度。灰度值越大,亮度越亮。范围一般为0-255,白色为255,黑色为0,因此黑白图片也称为灰度图像。

两种最常用的医学图像数据格式:

DICOM文件类型的后缀为,常用的python处理库有:,

NIFTI文件类型的后缀为,常用的python处理库有:,

:无论对于dcm还是nii图片的格式,只要是ct为了更好地观察不同的器官,可以选择将存储的原始数据转换为Hu值,因为Hu值代表物体的真实密度。

对于nii格式图片,SimpleITK,nibabel中常用的api界面将自动进行上述转换过程,即取出的值已经是Hu了。除非专门用nib.load('xx').dataobj.get_unscaled()或者itk.ReadImage('xx').GetPixel(x,y,z)获取原始数据

对于dcm格式图片,SimpleITK,pydicom常用的api接口不会自动将原始数据转换为Hu。(itk snap软件读入dcm或nii数据不会进行scale操作)

公式及代码:

HU = pixel_val*slope intercept

其中,slope,intercept可读取元数据

def get_pixels_hu(ct_array,slope,intercept):     if slope != 1:         ct_array = slope*ct_array     ct_array  = intercept     return ct_array

对于CT图像,它的HU值从负几千到正几千,我们可以用ITK依次读取CT图像的每个值,并可以将其每个值保存在Mat中此时通过opencv的imshow函数无法显示。图像显示和打印的一个问题是,图像的亮度和对比度不能完全突出关键部分。这里提到的关键部分是 CT 软组织、骨头、脑组织、肺、腹等。因为通常只有显示器 8-bit, 而数据有 12- 至 16-bits。也就是说,我们不能直接 CT 值作为传统意义上的像素值进行输出, 相反,它需要改变,或者称为映射。

研究人员对这些问题提出了一些要求 (requirements),变化应尽可能满足:

要求一:充分利用 0-255 间显示有效值域 要求2:尽量减少值域压缩造成的损失 要求3:组织部分不应突出损失

医学图像领域的窗口技术包括窗宽(window width)和窗位(window center),选择感兴趣的CT值范围。因为各种组织结构或病变有所不同CT因此,为了显示组织结构的细节,应选择适合观察组织或病变的窗宽和窗位,以获得最佳显示。窗宽和窗位对应图像的对比度和亮度。

:1)宽窗位是CT独特的图像概念,MRI图像中没有这个概念2)CT西安必须转换图像HU调整窗宽窗位值

是CT显示在图像上CT值范围,在此CT不同模拟灰度显示值范围内的组织和病变。而CT组织和病变的组织和病变,无论高程度如何,都以白影显示,不再有灰度差异; 相反,低于这一范围的组织结构,无论有多低,都以黑影显示,没有灰度差异。增加窗宽,图像显示CT增加值范围,显示不同密度的组织结构增加,但结构之间的灰度差减少。减少窗宽,显示的组织结构减少,但结构之间的灰度差增加。例如,观察大脑的窗宽通常为-15~ 85H,即密度在-15 ~ 85H脑质和脑脊液间隙等各种结构均以不同的灰度显示。而高于 85H骨质几颅内钙化等组织结构,虽然密度差,但白影显示,无灰度差;低于-15H皮下脂肪、乳突内气体等组织结构均以黑影显示,其间无灰度差异。

它是窗户的中心位置。由于窗户位置不同,窗户宽度相同。CT值范围的CT值也不同。例如,窗宽为1000H,当窗位为0H时,其CT值范围为-50 ~ 50H ; 如窗位为 35H时,则CT值范围为-15~ 85H。。例如脑质CT值约为 35H,在观察脑组织及其病变时,选择窗口 35H为妥。

应用场景:用神经网络分割liver 和 liver tumor,预处理训练数据。

基本思路:

窗位和窗宽可设置如下:(但有研究人员认为这种方法没有定制方法2的优势)

def get_window_size(organ_name):     if organ_name == 'lung':         # 肺部 ww 1500-2000 wl -450--600         center = -500         width = 2000     elif organ_name == 'abdomen':         # 腹部 ww 300-500 wl 30-50         center = 40         width = 500     elif organ_name == 'bone':         # 骨窗 ww 1000-1500 wl 250-350         center = 300         width = 2000     elif organ_name == 'lymph':         # 淋巴,软组织 ww 300-500 wl 40-60         center = 50         width = 300     elif organ_name == 'mediastinum':         # 纵隔 ww 250-350 wl 30-50         center = 40         width = 350     elif organ_name == 'liver':         #肝组织正常CT值为50HU左右,         #采用 ww 100-150 wl 70-75可以检查常规ww200,wl 50未检测到的病灶         #两种组织密度差小的病变适合观察高窗位和低窗宽         center == 70         width == 100         return center, width

1)用liver和tumor的mask抠出liver 和 tumor部分

2)统计相应的最大值和最小值,并用其计算窗宽窗位。

优点:每个case的窗宽窗位依据案例量身定做。相较于整个数据集用统一的窗宽窗位,或者采用cut off,有无可比拟的优点。

import SimpleITK as sitk
import numpy as np
import os

def saved_preprocessed(savedImg,origin,direction,xyz_thickness,saved_name):
    newImg = sitk.GetImageFromArray(savedImg)
    newImg.SetOrigin(origin)
    newImg.SetDirection(direction)
    newImg.SetSpacing((xyz_thickness[0], xyz_thickness[1], xyz_thickness[2]))
    sitk.WriteImage(newImg, saved_name)

def window_transform(ct_array, windowWidth, windowCenter, normal=False):
    """
    return: trucated image according to window center and window width
    and normalized to [0,1]
    """
    minWindow = float(windowCenter) - 0.5*float(windowWidth)
    newing = (ct_array - minWindow)/float(windowWidth)
    newing[newing < 0] = 0
    newing[newing > 1] = 1
    #将值域转到0-255之间,例如要看头颅时, 我们只需将头颅的值域转换到 0-255 就行了
    if not normal:
        newing = (newing *255).astype('uint8')
    return newing

ct_path = 'G:\LITS\Training_dataset'
saved_path = 'C:\\Users\\Cerry\\Desktop\\wl'
name_list = ['volume-0.nii']
for name in name_list:
    ct = sitk.ReadImage(os.path.join(ct_path,name))
    origin = ct.GetOrigin()
    direction = ct.GetDirection()
    xyz_thickness = ct.GetSpacing()
    ct_array = sitk.GetArrayFromImage(ct)
    seg_array = sitk.GetArrayFromImge(sitk.ReadImage(os.path.join(ct_path,name.replace('volume'
                                                                       ,'segmentation'))))

seg_bg = seg_array == 0
seg_liver = seg_array >= 1
seg_tumor = seg_array == 2

ct_bg = ct_array * seg_bg
ct_liver = ct_array*seg_liver
ct_tumor = ct_array*seg_tumor

liver_min = ct_liver.min()
liver_max = ct_liver.max()
tumor_min = ct_tumor.min()
tumor_max = ct_tumor.max()

#by liver
liver_wide = liver_max - liver_min
liver_center = (liver_max + liver_min)/2
liver_wl = window_transform(ct_array,liver_wide,liver_center,normal=True)
saved_name = os.path.join(saved_path,'liver_w1_1.nii')
saved_preprocessed(liver_w1,origin,direction,xyz_thickness,saved_name)

#by tumor(recommended)
tumor_wide = tumor_max - tumor_min
tumor_center = (tumor_max + tumor_min) / 2
tumor_wl = window_transform(ct_array, tumor_wide, tumor_center, normal=True)
saved_name = os.path.join(saved_path, 'tumor_wl_1.nii')
saved_preprocessed(tumor_wl, origin, direction, xyz_thickness, saved_name)

:有研究者认为如果用下面的公式来实现,实验结果会非常的糟糕!

#先算图像的最大和最小值
min = (2*window_center - window_width)/2.0 + 0.5
max = (2*window_center + window_width)/2.0 + 0.5
for i in range(nNumPixels):
    disp_pixel_val = (pixel_val - min)*255.0/(max - min)


#或者:
dFactor = 255.0 / (max - min)
    d, h, w = np.shape(img)
    for n in np.arange(d):
        for i in np.arange(h):
            for j in np.arange(w):
                img[n, i, j] = int((img[n, i, j] - min) * dFactor)



min_index = img < 0
img[min_index] = 0
max_index = img > 255
img[max_index] = 255

return img
 

CT图像不同扫描面的像素尺寸、粗细粒度是不同的,这对进行CNN有不好的影响,因此可能需要进行重构采样,这里可参考CT图像相关知识与SimpleITK的使用介绍的12

并且,为了更好地进行网络训练,通常采用数据归一化。

CT图像之Hu值变换与窗宽窗位调整

医学影像“调窗”(window-leveling)的算法

CT图像的相关知识

标签: ct7731钳式传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台