摘要

目前正在做肾脏肿瘤的预处理问题,比赛地址。
KiTS19 年比赛的 结果。
JunMa大佬在自己的知乎里面给出了自己的看法和对于论文的学习与展望。

我最近正在解决数据预处理的问题,论文的数据预处理分为了重采样,spacing 到 3.22mmx1.62mmx1.62mm,然后将灰度值cut off到[-79,304],然后将cut off 之后的数据进行z-score(subtract 101 and divide by 76.9 to bring the intensity values in a range that is
more easily processed by CNNs)。最后将输入神经网络的数据大小定为80x160x160。

重采样

首先强调一下,我对于论文的复现来自于我对于论文的解读以及自己代码水平,不一定对,但是提供一个思路
我一开始对于spacing到3.22mmx1.62mmx1.62mm表示十分的不理解,像素之间的距离难道不都是1吗?像素距离和实际测量的毫米有什么关系,后来我才知道,CT图像里面是保存有图像的pixdim信息的。具体代码如下

 #img_name 就是一个nii.gz文件的地址img = nibabel.load(img_name)pix_dim = (img.header.structarr['pixdim'][1],img.header.structarr['pixdim'][2],img.header.structarr['pixdim'][3])print(pix_dim)

这样就可以读取pixdim数据我的第一个图片的数据是(0.5mm, 0.9199219mm,0.9199219mm)也就是说它的实际spacing是这个。使用skimage里面的transform.rescale()就可以把数据处理成自己想要得spacing,具体写法如下(对于image的操作)

 from skimage import transformtarget_resolution = (3.22,1.62,1.62)img = np.array(img.get_data())scale_vector = (pix_dim[0]/target_resolution[0],pix_dim[1]/target_resolution[1],pix_dim[2]/target_resolution[2])"""order = 1 样条插值的顺序,必须是在0-5范围内,默认是1,详情参见skimage.transform.warp 这个很重要mode = {'constant','edge','symmetric','reflect','warp'}可选输入边界之外的点根据到给定的模式,模式匹配行为'numpy.pad'cval 与模式constant结合使用,外部值图像边界剪辑 : bool 可选, 是否将输出剪辑到输入值范围,这是默认启用的,因为高阶线性插值可能产生超出给定输入值的范围。preserve_range : bool 可选  是否保持原始值的范围。否则输入图像根据img_as_float的约定进行转换 详情: https://scikit-image.org/docs/dev/user_guide/data_types.htmlmultichannel : bool 可选 图像的最后一个轴是否被解释为多个通道或者空间维度。anti_aliasing : bool 可选 是否用高斯滤波器来平滑图像,缩小比例。将图像下采样到避免解释为多个渠道或者其他空间维度避免混叠伪影anti_aliasing_sigma : {float, tuple of floats} optional 高斯滤波的标准差,以避免混叠伪影,默认情况下,此值选择为(1-2)/2,其中s是缩小比例因子"""yinzi = transform.rescale(img, scale_vector,order=1, mode='constant', cval=0, clip=True,preserve_range=True, multichannel=False,anti_aliasing=True, anti_aliasing_sigma=None)

scale_vector 是 pixdim和target_resolution的比值,对于这个rescale真的有很多参数,如果不想改变原来的值就把order=0,并且把anti_aliasing=False ,并且把preserve_range=True(这个真的特别重要), 因为如果不这样的话,mask里面的数据只有[0,1,2],rescale之后数据就会变得很乱很乱,对于mask的操作如下

 img = nibabel.load(img_name)print(img.shape)pix_dim = (img.header.structarr['pixdim'][1],img.header.structarr['pixdim'][2],img.header.structarr['pixdim'][3])print('pix_dim',pix_dim)img = np.array(img.get_data())print('non_transpos_shape',img.shape)print(np.unique(img))target_resolution = (3.22,1.62,1.62)scale_vector = (pix_dim[0] / target_resolution[0],pix_dim[1] / target_resolution[1],pix_dim[2] / target_resolution[2])img = img.astype(np.float)print('img.dtype', img.dtype)print(np.unique(img))# uint8# 这里把uint8转换成了float64了yinzi = transform.rescale(img, scale_vector,order=0, mode='constant', cval=0, clip=True,preserve_range=True, multichannel=False,anti_aliasing=False, anti_aliasing_sigma=None)

这里比较建议大家去读一读源码里面的注释,然后参考输入输出类型的解释的官方页面进行学习。

窗体变换+强度裁剪

强度裁剪

ct_array[ct_array < -79.0] = -79.0
ct_array[ct_array > 304.0] = 304.0

z-score

newimg = (ct_array - 101) / float(76.9)

crop成(80,160,160)

这个真的是自己瞎编了,我用最传统的赋值方法做的,具体对不对我也不知道了
代码:

def z_crop(img_array,crop_array,z,xy):if z >= 80 and xy >= 160:side = z - 80startz = side//2endnum = side - startzendz = z - endnumstartxy = (xy-160)//2endxy = xy - ((xy-160)-startxy)crop_array[:,:,:] = img_array[startz:endz,startxy:endxy,startxy:endxy]elif z>=80 and xy < 160:side = z - 80startz = side//2endnum = side - startzendz = z - endnumstartxy = (160 - xy) // 2endxy = 160 - ((160 - xy) - startxy)crop_array[:,startxy:endxy,startxy:endxy] = img_array[startz:endz,:,:]elif z < 80 and xy >= 160:side =  80 - zstartz = side//2endnum = side - startzendz = 80 - endnumstartxy = (xy-160)//2endxy = xy - ((xy-160)-startxy)crop_array[startz:endz,:,:] = img_array[:,startxy:endxy,startxy:endxy]elif z < 80 and xy < 160:side =  80 - zstartz = side//2endnum = side - startzendz = 80 - endnumprint(side)print(startz)print(endnum)print(endz)startxy = (160 - xy) // 2endxy = 160 - ((160 - xy) - startxy)crop_array[startz:endz,startxy:endxy,startxy:endxy] = img_array[:,:,:]return crop_array

最后转换成np文件

def preprocessingtonp(pathImg_list):for subsetindex in range(len(pathImg_list)):try:print(pathImg_list[subsetindex])subset_path = KiTs_path + "/" + str(pathImg_list[subsetindex]) + deal_name # 改成计算groundtruthsubmask_path = KiTs_path + "/" + str(pathImg_list[subsetindex]) + dealseg_name#这个地方可以随便写的,如果写斜杠或者反斜杠都可以#print(subset_path)# cropimg_src = sitk.ReadImage(subset_path,sitk.sitkFloat64)img_array = sitk.GetArrayFromImage(img_src)mask_src = sitk.ReadImage(submask_path,sitk.sitkInt8)mask_array = sitk.GetArrayFromImage(mask_src)print(img_array.shape)print(mask_array.shape)print(type(img_array))print(type(mask_array))print(img_array.max())print(img_array.min())print(mask_array.max())print(mask_array.min())file_path = outputImg_path + "/" + str(pathImg_list[subsetindex]) + ".npy"mask_path = outputMask_path + "/" + str(pathImg_list[subsetindex]) + ".npy"## np.save(file_path, img_array)# np.save(mask_path,mask_array)except:subset_path = KiTs_path + "/" + str(pathImg_list[subsetindex]) + image_nameprint(subset_path,"不行")

总结一下

就这不到500行代码写了将近10天,我感觉比较难的地方第一个是重采样部分,要是不是学长给了我一段代码我现在都不知道如何resampling,第二个是transform.rescale,我一开始没有想过后面那些参数这么重要,我一开始就只传入了一个image,一个scale因子的范围,没想到处理mask 一个 order=0 一个mode=“constant” 一个preserve_range=True 一个anti_aliasing=False 一套连招才能处理好mask,读源码的重要性不言而喻。
最后crop我也是瞎几把crop的,我没有根据肾脏的部位来,直接crop中间,我看了看有些数据集还是切到了mask,我也不知道该怎么办了,去他妈的吧,先去训练了。
窗体裁剪也是我自己随着性子写的,网上给了一套方法,我一开始也是按照他的想法写的,虽然总感觉不对劲,但是这篇博客写的基础知识还是很全面的,建议大家可以看一下。

参考资料

https://kits19.grand-challenge.org/
http://results.kits-challenge.org/miccai2019/
https://zhuanlan.zhihu.com/p/76057976
https://scikit-image.org/docs/dev/user_guide/data_types.html
https://blog.csdn.net/normol/article/details/88313888
https://blog.csdn.net/qq_34532604/article/details/104206045
这篇讲重采样不错

KITS+肾脏肿瘤预处理+重采样+窗体变换+强度裁剪相关推荐

  1. nnUnet肾脏肿瘤分割实战(KiTS19)

    nnUnet肾脏肿瘤分割实战 KiTS19 Challenge Homepage nnunet项目官方地址 MIC-DKFZ/nnUNet 使用nnunet之前,建议先阅读两篇论文 nnU-Net: ...

  2. cv图像预处理——逐像素变换

    cv图像预处理--逐像素变换 标签:计算机视觉 逐像素变换 对图像中的每个像素逐个进行处理. 白化(类似于标准化) 白化的目的是要为图像的平均亮度水平和对比度提供波动的恒定性.其中每个像素进行如下转换 ...

  3. Halcon图像预处理-图像的变换与校正

    提示:本文参考了网上其他相关文章,如有侵权,请联系作者. 文章目录 前言 一.图像处理与矩阵(Matrix).齐次坐标 1.图像的平移 2.图像的旋转 3.图像的缩放 4.补充 二.仿射变换 1.仿射 ...

  4. 使用nnUNet训练肾脏肿瘤分割数据集KiTS19(仅用于记录)

    按照nnUNet官方下载配置好 准备好KiTS19数据,任务id设为40 1. 运行nnunet/dataset_conversion下的Task040_KiTS.py, 需要对Json的写入文件名进 ...

  5. 医学图像预处理----重采样(Resample)

    前言: 在医学图像中,重采样是指将医疗图像中大小不同的体素归一化到相同的大小.体素是体积元素(Volume Pixel)的简称,一张3D医学图像可以看成是由若干个体素构成的,体素是一张3D医疗图像在空 ...

  6. matlab标准化还原,1.2基于MATLAB的数据预处理(标准化变换部分)

    紧接上文 1.离差标准化:对原始数据的一种线性变换,将原始数据的数值映射到[0,1]区间,公式如下: 用x到最小值的距离除以最大值到最小值的距离,也可理解为最小值为起点,最大值为终点,各点到起点的距离 ...

  7. 医学图像分割实战——使用U-Net实现肾脏CT分割

    使用U-Net实现肾脏CT分割 数据集准备 数据来源 数据预处理 网络结构及代码 网络结构 训练代码 训练过程 参数设置: 可视化 结果分析 数据集准备 数据来源 MICCAI KiTS19(Kidn ...

  8. 解读6大常见肿瘤的消融选择

    随着全球癌症负担人口的逐渐增加,以及微创消融治疗癌症的日渐普及,肿瘤消融将会在更多肿瘤疾病中发挥越来越重要的作用,逐渐形成癌症治疗的新格局. 文章来源:思宇MedTech :编辑:祎禾 转载要求:首发 ...

  9. 数据预处理与特征工程—12.常见的数据预处理与特征工程手段总结

    文章目录 引言 1.数据预处理 1.1 数据清洗 1.1.1 异常值处理 1.1.2 缺失值处理 1.2 特征预处理 1.2.1 数值型特征无量纲化 1.2.2 连续数值型特征分箱 1.2.2.1 无 ...

最新文章

  1. 【超详细】DBCP连接池配置参数说明
  2. 商城项目-商品添加功能实现
  3. 大话数据结构02 :线性表链式存储 C++
  4. linux内核开发_Linux 内核的代码仓库管理与开发流程简介
  5. java jvm调优_(第1部分,共3部分):有关性能调优,Java中的JVM,GC,Mechanical Sympathy等的文章和视频的摘要...
  6. Java毕业设计--健康推广管理系统项目实战【Springboot+mybatis+layui等实现】
  7. js转义字符 php 反转义6,JS实现HTML标签转义及反转义
  8. 【git clone 报错】fatal: unable to access ‘https://github.com/zimeng303/React.git/‘: Failed to connect
  9. 人工智能在fpga的具体应用_新基建“芯”机遇,国产FPGA厂商如何抓住机会?
  10. Java中hashCode()与 equals()
  11. 数字逻辑设计(3)------卡诺图化简
  12. 系统找不到指定的文件
  13. linux编译ipp多线程,Linux下Intel IPP编程环境的配置
  14. adguard没有核心 core no_树莓派安装AdGuard Home屏蔽广告
  15. div:给div加滚动条 div的滚动条设置
  16. 云产品经理相关技术知识(一)
  17. 限制字符输入数功能(jQ版和原生JS版)
  18. 前端设计-css网格布局的最佳实践
  19. 思科服务器如何重装系统,【干货】思科 ios 软件的安装升级方法
  20. 安防监控系统流媒体服务器,搭建一套安防监控系统RTSP/Onvif网络摄像头视频流媒体服务有哪些核心要素?...

热门文章

  1. 高阶自动驾驶量产之战,小鹏汽车NGP究竟有何优势?
  2. 支付宝接口申请流程-傲付宝
  3. android项目源码解析04:新浪微博客户端源码解析
  4. “数据不会说谎”,如何看穿大数据背后的真相?
  5. 2020年浙江大学软件学院推免面试
  6. CloudManage介绍
  7. 个人电脑和虚拟web服务器对比,用pws来构建自己的WEB服务器
  8. 1.ROS环境搭建与基础工作
  9. LLVM每日谈之四十一 组装一个完整的工具链
  10. Rust AES加密、解密工具