医工互联

 找回密码
 注册[Register]

手机动态码快速登录

手机号快速登录

微信登录

微信扫一扫,快速登录

QQ登录

只需一步,快速开始

查看: 320|回复: 0
收起左侧

医学图像预处理(三)——windowing(ct对比增强)

[复制链接]

  离线 

发表于 2022-10-30 22:39:23 | 显示全部楼层 |阅读模式 <
若是dicom格式的图片,得先转化为hu值(即ct图像值,若图片本来就是ct,则不需要转换)(见下面更新内容) ,因为hu值是与设备无关的,不同范围之内的值可以代表不同器官。常见的对应如下(w代表ct值width,L代表ct值level,即 [level - width/2 , level + width/2]为其窗口化目标范围):
2019-7-24更新
其实无论对于dcm还是nii格式的图片,只要是ct图,就都可以选择将储存的原始数据转化为Hu值,因为Hu值即代表了物体真正的密度。
对于nii格式的图片,经过测试,nibabel, simpleitk常用的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操作)
下面是做的测试
  1. import nibabel as nib
  2. import SimpleITK as itk
  3. import pydicom
  4. nii_file = r'G:\data\LITS17\LITS17_vol\volume-0.nii'
  5. dcm_file = r'G:\data\3Dircadb\3Dircadb1.1\PATIENT_DICOM\image_0'
  6. img = nib.load(nii_file)
  7. """
  8. 经过测试get_fdata会自动根据头文件数据中的
  9. inter, slope 将raw data转换到hu data
  10. img.dataobj.get_unscaled获取的就是未转化的
  11. raw data。还需要注意的是,img.header中的
  12. scl_slope, scl_inter为nan,因为对于转换后的
  13. hu data而言,这两个值已经不重要了
  14. 想要知道的话,可以专门用
  15. img.dataobj.slope, img.dataobj.inter 获取
  16. """
  17. hu_data = img.get_fdata()  # Hu data
  18. pixel_data = img.dataobj.get_unscaled() # raw data
  19. seg = itk.ReadImage(nii_file)
  20. segimg = itk.GetArrayFromImage(seg)  # == img.get_fdata(), Hu data
  21. print(seg.GetPixel(0, 0, 0))  # unscale, raw data
  22. """经过测试,itk里的头文件不会像nib将inter和slope抹去"""
  23. # for key in seg.GetMetaDataKeys():
  24. #     print("{0}:{1}".format(key, seg.GetMetaData(key)))
  25. print('---------------')
  26. dcm_itk = itk.ReadImage(dcm_file)
  27. # for key in dcm_itk.GetMetaDataKeys():
  28. #     print("{0}:{1}".format(key, dcm_itk.GetMetaData(key)))
  29. print(dcm_itk.GetPixel(0, 0, 0))  # -1024 unscaled, raw data
  30. data_itk = itk.GetArrayFromImage(dcm_itk)
  31. print(data_itk)  # -1024,unscaled, raw data
  32. print(pydicom.dcmread(dcm_file).pixel_array)  # == data_itk,unscaled, raw data
复制代码
234003pxskk47qxxss2kcs.png



dicom转化为hu的示例代码

如下:
  1. def get_pixels_hu(scans):
  2.     #type(scans[0].pixel_array)
  3.     #Out[15]: numpy.ndarray
  4.     #scans[0].pixel_array.shape
  5.     #Out[16]: (512, 512)
  6.     # image.shape: (129,512,512)
  7.     image = np.stack([s.pixel_array for s in scans])
  8.     # Convert to int16 (from sometimes int16),
  9.     # should be possible as values should always be low enough (<32k)
  10.     image = image.astype(np.int16)
  11.     # Set outside-of-scan pixels to 1
  12.     # The intercept is usually -1024, so air is approximately 0
  13.     image[image == -2000] = 0
  14.    
  15.     # Convert to Hounsfield units (HU)
  16.     intercept = scans[0].RescaleIntercept
  17.     slope = scans[0].RescaleSlope
  18.    
  19.     if slope != 1:
  20.         image = slope * image.astype(np.float64)
  21.         image = image.astype(np.int16)
  22.         
  23.     image += np.int16(intercept)
  24.    
  25.     return np.array(image, dtype=np.int16)
复制代码
windowing

然而,hu的范围一般来说很大,这就导致了对比度很差,如果需要针对具体的器官进行处理,效果会不好,于是就有了windowing的方法:
   Windowing, also known as grey-level mapping, contrast stretching, histogram modification or contrast enhancement is the process in which the CT image greyscale component of an image is manipulated via the CT numbers; doing this will change the appearance of the picture to highlight particular structures. The brightness of the image is, adjusted via the window level. The contrast is adjusted via the window width.
  图像的亮度取决于window level,图像的对比度取决于window width。
234004c7f6lz63kztkve6q.png

Window width

   The window width (WW) as the name suggests is the measure of the range of CT numbers that an image contains.
  窗口宽度就是一幅ct图片包含的ct值范围。
   A wider window width (2000 HU), therefore, will display a wider range of CT numbers. Consequently, the transition of dark to light structures will occur over a larger transition area to that of a narrow window width (<1000 HU).
  更宽的窗口,相对于窄的窗口来说,从暗到亮的结构过度将会在发生在更大的过度区域。
   Accordingly, it is important to note, that a significantly wide window displaying all the CT numbers will result in different attenuations between soft tissues to become obscured.
  因此,一个展示了所有ct值的宽窗口,将导致软组织间不同的ct值变得模糊。
Wide window

   Defined as 400-2000 HU best used in areas of acute differing attenuation values, a good example is lungs or cortical tissue, where air and vessels will sit side by side.
  宽窗口经常用于ct值变化很大的领域,比如肺部或外皮组织,这些地方空气和血管将会一同出现。
Narrow window

   Defined as 50-350 HU are excellent when examining areas of similar attenuation, for example, soft tissue.
  窄的窗口常用于ct值相似的区域,例如软组织。
Window level/center

   The window level (WL), often also referred to as window center, is the midpoint of the range of the CT numbers displayed.
  窗口水平,也经常成为窗口中心,是ct值的中点。
   When the window level is decreased the CT image will be brighter and vice versa.
  窗口level减少,图片将变亮,level增大,图片变暗。
Upper and lower grey level calculation

   When presented with a WW and WL one can calculate the upper and lower grey levels i.e. values over x will be white and values below y will be black.
  当给定了window width和window level后,就能计算出窗口的上下界。
超过上界的,是白色,低于下界的,是黑色。
下面是计算方法和举例。
   the upper grey level (x) is calculated via WL + (WW ÷ 2)
the lower grey level (y) is calculated via WL - (WW ÷ 2)
    For example, a brain is W:80 L:40, therefore, all values above +80 will be white and all values below 0 are black.
  windowing代码

  1. def transform_ctdata(self, windowWidth, windowCenter, normal=False):
  2.         """
  3.         注意,这个函数的self.image一定得是float类型的,否则就无效!
  4.         return: trucated image according to window center and window width
  5.         """
  6.         minWindow = float(windowCenter) - 0.5*float(windowWidth)
  7.         newimg = (self.image - minWindow) / float(windowWidth)
  8.         newimg[newimg < 0] = 0
  9.         newimg[newimg > 1] = 1
  10.         if not normal:
  11.             newimg = (newimg * 255).astype('uint8')
  12.         return newimg
复制代码
2019-10-9 更新
windowCenter和windowWidth的选择:
一是可以根据所需部位的hu值(对于CT数据而言)分布范围选取(注意若是增强ct的话hu值会有一些差别,可以画一下几个随机数据的hu分布图看一看)
二是可以根据图像的统计信息,例如图像均值作为窗口中心,正负2.5(这个值并非固定)的方差作为窗口宽度
下面是github上,vnet一个预处理过程,使用了基于统计的窗口化操作
  1. class StatisticalNormalization(object):
  2.     """
  3.     Normalize an image by mapping intensity with intensity distribution
  4.     """
  5.     def __init__(self, sigma):
  6.         self.name = 'StatisticalNormalization'
  7.         assert isinstance(sigma, float)
  8.         self.sigma = sigma
  9.     def __call__(self, sample):
  10.         image, label = sample['image'], sample['label']
  11.         statisticsFilter = sitk.StatisticsImageFilter()
  12.         statisticsFilter.Execute(image)
  13.         intensityWindowingFilter = sitk.IntensityWindowingImageFilter()
  14.         intensityWindowingFilter.SetOutputMaximum(255)
  15.         intensityWindowingFilter.SetOutputMinimum(0)
  16.         intensityWindowingFilter.SetWindowMaximum(
  17.             statisticsFilter.GetMean() + self.sigma * statisticsFilter.GetSigma())
  18.         intensityWindowingFilter.SetWindowMinimum(
  19.             statisticsFilter.GetMean() - self.sigma * statisticsFilter.GetSigma())
  20.         image = intensityWindowingFilter.Execute(image)
  21.         return {'image': image, 'label': label}
复制代码
来源:https://blog.csdn.net/normol/article/details/88313888
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

提醒:禁止复制他人回复等『恶意灌水』行为,违者重罚!
您需要登录后才可以回帖 登录 | 注册[Register] 手机动态码快速登录 微信登录

本版积分规则

发布主题 快速回复 收藏帖子 返回列表 客服中心 搜索
简体中文 繁體中文 English 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french

QQ|RSS订阅|小黑屋|处罚记录|手机版|联系我们|Archiver|医工互联 |粤ICP备2021178090号 |网站地图

GMT+8, 2024-11-25 05:08 , Processed in 0.297946 second(s), 69 queries .

Powered by Discuz!

Copyright © 2001-2023, Discuz! Team.

快速回复 返回顶部 返回列表