LUNA16结节可视化及世界(CT)坐标与体素(图像)坐标的转换
这个是关于DCM的医学坐标系的一些背景知识,本文将在此基础上做些补充。
DICOM医学图像读取涉及到的医学坐标体系_sunyao_123的博客-CSDN博客_dicom坐标系
关于坐标名称,看了许多博文,有像素坐标,真实坐标,体素坐标,图像坐标,世界坐标搞得一头雾水。本文中CT坐标指的是设备拍摄时的坐标,单位为mm。图像坐标指的是转化为numpy后的坐标,单位为单位1。自己的理解世界坐标应该是CT坐标,体素坐标,像素坐标,真实坐标及图像坐标应该都是图像坐标。
一 、 肺部图像的转化
首先,CT图像的坐标原点是左上角,和将CT图像转为numpy格式的坐标原点一致,方便处理。
其次,CT图像的像素间距与像素原点每个case都不同具体和拍摄设备参数相关,会将这些参数存储到mha文件中。以下图为例,此case中的CT像素间隔和原点坐标分别为
Spacing[x ,y, z] = [0.73242199, 0.73242199, 1.25]
Origin[x ,y, z] = [-163.199997, -145.5, -380.] 单位都是mm。而像素个数为512*512*305也就是转成numpy后,数组的shape为[305, 512, 512]。
我的理解是在图像坐标中图像的像素间隔为单位1,CT坐标下像素间隔为spacing,真实的图像大小应为转为numpy的shape乘上spacing。
new_size = data.shape * numpySpacing[::-1] data.shape的输出顺序为(z, y, x)故相乘时需要将numpySpacing也反序。new_size为CT图像的真实大小单位为mm。
在可视化肺结节时我们使用的是图像坐标,故需要将肺结节的坐标也转化为图像坐标。
itkImage = sitk.ReadImage('D:/BaiduNetdiskDownload/LUNA16/subset9/1.3.6.1.4.1.14519.5.2.1.6279.6001.153985109349433321657655488650.mhd')numpyOrigin = np.array(list(itkImage.GetOrigin()))numpySpacing = np.array(list(itkImage.GetSpacing()))print(numpyOrigin,numpySpacing)data = sitk.GetArrayFromImage(itkImage)print(data.shape)new_size = data.shape * numpySpacing[::-1]print(new_size)
# 输出结果
[-163.199997 -145.5 -380. ] [0.73242199 0.73242199 1.25 ]
(305, 512, 512)
[381.25 375.00006104 375.00006104]
二、肺结节的坐标转化
以上述case为例,肺结节的坐标信息如下。分别是ID,x,y,z,半径。单位是mm。
转化的公式:图像坐标 = CT坐标系下的(结节位置 - 原点位置) / 像素间隔
def worldToVoxelCoord(worldCoord, origin, spacing):# 图像坐标系的结节位置 = CT坐标系下的(结节位置 - 原点位置) / 体素间隔stretchedVoxelCoord = np.absolute(worldCoord - origin)voxelCoord = stretchedVoxelCoord / spacingreturn voxelCoord
三、可视化
显示代码转载自: LUNA16数据集(二)肺结节可视化 - 走看看
def show_nodules(ct_scan, nodules, radius=20, pad=5, max_show_num=3): # 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: continuex, y, z = int(nodules[idx, 0]), int(nodules[idx, 1]), int(nodules[idx, 2])data = ct_scan[z]# 注意 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: # 检查是否有结节在同一张切片,如果有,只显示一张continueshow_index.append(z)plt.figureplt.imshow(data, cmap='gray')plt.show()
数据准备代码:
itkImage = sitk.ReadImage('D:/BaiduNetdiskDownload/LUNA16/subset9/1.3.6.1.4.1.14519.5.2.1.6279.6001.153985109349433321657655488650.mhd')numpyOrigin = np.array(list(itkImage.GetOrigin()))numpySpacing = np.array(list(itkImage.GetSpacing()))print(numpyOrigin,numpySpacing)data = sitk.GetArrayFromImage(itkImage)print(data.shape)new_size = data.shape * numpySpacing[::-1]print(new_size)annos = np.array(pandas.read_csv('D:/BaiduNetdiskDownload/LUNA16/CSVFILES/annotations.csv'))# 图像相应的结节信息annos = annos[198,1:]# CT坐标转为图像坐标annos1 = worldToVoxelCoord(annos[:3],numpyOrigin,numpySpacing)# 结节半径也转为图像坐标annos = np.concatenate([annos1,[annos[3]/numpySpacing[1]]])annos = np.expand_dims(annos,axis=0)print(annos.shape)show_nodules(data,annos)
结果显示:
LUNA16结节可视化及世界(CT)坐标与体素(图像)坐标的转换相关推荐
- 图像坐标:我想和世界坐标谈谈(B)
二.图像坐标:我想和世界坐标谈谈(B) 玉米将在这篇博文中,对图像坐标与世界坐标的这场对话中涉及的第二个问题:谈话方式,进行总结.世界坐标是怎样变换进摄像机,投影成图像坐标的呢? 玉米做了一个简单的图 ...
- 图像坐标:我想和世界坐标谈谈(A) 【计算机视觉学习笔记--双目视觉几何框架系列】
玉米竭力用轻松具体的描述来讲述双目三维重建中的一些数学问题.希望这样的方式让大家以一个轻松的心态阅读玉米的<计算机视觉学习笔记>双目视觉数学架构系列博客.这个系列博客旨在捋顺一下已标定的双 ...
- matlab 相机焦距,世界坐标、相机坐标、图像坐标、像素坐标的原理、关系,并用matlab仿真...
照相机是日常生活中最常见的.它能把三维的空间图片等比例缩小投影在照片上,称为一个二维图像. 以下我们就讲一讲原理,并相应的进行matlab仿真. 在学之前,先要了解几个概念: 什么是世界坐标? 也就是 ...
- R语言ggplot2可视化:指定标题的坐标轴位置(X轴坐标和Y轴坐标),将图像的标题(title)放置在图像内部的指定位置(customize title positon in plot)
R语言ggplot2可视化:指定标题的坐标轴位置(X轴坐标和Y轴坐标),将图像的标题(title)放置在图像内部的指定位置(customize title positon in plot) 目录
- Matplotlib可视化散点图、配置X轴为对数坐标、并使用线条(line)连接散点图中的数据点、基于分组变量配置数据点的颜色(connecting two coordinates with line
Matplotlib可视化散点图.配置X轴为对数坐标.并使用线条(line)连接散点图中的数据点.基于分组变量配置数据点的颜色(connecting two coordinates with line ...
- Matplotlib可视化散点图、配置X轴为对数坐标、并使用线条(line)连接散点图中的数据点(Simple Line Plot with Data points in Matplotlib)
Matplotlib可视化散点图.配置X轴为对数坐标.并使用线条(line)连接散点图中的数据点(Simple Line Plot with Data points in Matplotlib) 目录
- R语言ggplot2可视化强制设置x轴、y轴坐标的起始点为0或者其他实战
R语言ggplot2可视化强制设置x轴.y轴坐标的起始点为0或者其他实战 目录 R语言ggplot2可视化强制设置x轴.y轴坐标的起始点为0或者其他实战
- 我的世界服务器国际版显示坐标,我的世界国际版怎么一直显示坐标 | 手游网游页游攻略大全...
发布时间:2016-07-22 我的世界手机版中与PC版一样有边境之地,那么边境之地怎么去呢?99安卓网小编下面分享我的世界手机版边境之地坐标和走法,供参考. x:1000 y:1000边境之地 我的 ...
- 相机标定(二)——图像坐标与世界坐标转换
相机标定(一)--内参标定与程序实现 相机标定(二)--图像坐标与世界坐标转换 相机标定(三)--手眼标定 一.坐标关系 相机中有四个坐标系,分别为world,camera,image,pixel w ...
最新文章
- JavaScript原型与原型链(总结篇)
- Java中善用通用的枚举对象类实现代码业务的判断
- 搭建TFS2008的过程及其注意事项
- Windows下Git Bash Here怎么整个文件夹目录上传到代码仓库(不论GitHub、GitLab、Gitee、DevCloud)
- 谷歌浏览器实现直接打印效果
- 闲鱼发布2020租房报告:每天近万人在闲鱼找室友
- 洛谷P1313 计算系数【快速幂+dp】
- android的四大组件及使用场景,Android/四大组件/Activity.md · BoraxZYF/AndroidInterview - Gitee.com...
- 曾经的那些绝世电脑高手们
- 四旋翼飞行器——飞行原理
- 牛X的规则引擎urule2
- H5标签datalist
- 无人机倾斜摄影技术在不动产项目中的实际运用
- 16天7000dict
- 说说自己工作中的测试流程
- 太厉害了!我用 Nginx 提升系统10倍性能
- 高并发如何处理,解决方案
- Phalloidin——Acti-stain555鬼笔环肽研究
- C#圆形卡尺测量程序基于halcon
- 【新示例】阿里系行业SaaS,企加云要做IOE的赋能者