这个是关于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)坐标与体素(图像)坐标的转换相关推荐

  1. 图像坐标:我想和世界坐标谈谈(B)

    二.图像坐标:我想和世界坐标谈谈(B) 玉米将在这篇博文中,对图像坐标与世界坐标的这场对话中涉及的第二个问题:谈话方式,进行总结.世界坐标是怎样变换进摄像机,投影成图像坐标的呢? 玉米做了一个简单的图 ...

  2. 图像坐标:我想和世界坐标谈谈(A) 【计算机视觉学习笔记--双目视觉几何框架系列】

    玉米竭力用轻松具体的描述来讲述双目三维重建中的一些数学问题.希望这样的方式让大家以一个轻松的心态阅读玉米的<计算机视觉学习笔记>双目视觉数学架构系列博客.这个系列博客旨在捋顺一下已标定的双 ...

  3. matlab 相机焦距,世界坐标、相机坐标、图像坐标、像素坐标的原理、关系,并用matlab仿真...

    照相机是日常生活中最常见的.它能把三维的空间图片等比例缩小投影在照片上,称为一个二维图像. 以下我们就讲一讲原理,并相应的进行matlab仿真. 在学之前,先要了解几个概念: 什么是世界坐标? 也就是 ...

  4. R语言ggplot2可视化:指定标题的坐标轴位置(X轴坐标和Y轴坐标),将图像的标题(title)放置在图像内部的指定位置(customize title positon in plot)

    R语言ggplot2可视化:指定标题的坐标轴位置(X轴坐标和Y轴坐标),将图像的标题(title)放置在图像内部的指定位置(customize title positon in plot) 目录

  5. Matplotlib可视化散点图、配置X轴为对数坐标、并使用线条(line)连接散点图中的数据点、基于分组变量配置数据点的颜色(connecting two coordinates with line

    Matplotlib可视化散点图.配置X轴为对数坐标.并使用线条(line)连接散点图中的数据点.基于分组变量配置数据点的颜色(connecting two coordinates with line ...

  6. Matplotlib可视化散点图、配置X轴为对数坐标、并使用线条(line)连接散点图中的数据点(Simple Line Plot with Data points in Matplotlib)

    Matplotlib可视化散点图.配置X轴为对数坐标.并使用线条(line)连接散点图中的数据点(Simple Line Plot with Data points in Matplotlib) 目录

  7. R语言ggplot2可视化强制设置x轴、y轴坐标的起始点为0或者其他实战

    R语言ggplot2可视化强制设置x轴.y轴坐标的起始点为0或者其他实战 目录 R语言ggplot2可视化强制设置x轴.y轴坐标的起始点为0或者其他实战

  8. 我的世界服务器国际版显示坐标,我的世界国际版怎么一直显示坐标 | 手游网游页游攻略大全...

    发布时间:2016-07-22 我的世界手机版中与PC版一样有边境之地,那么边境之地怎么去呢?99安卓网小编下面分享我的世界手机版边境之地坐标和走法,供参考. x:1000 y:1000边境之地 我的 ...

  9. 相机标定(二)——图像坐标与世界坐标转换

    相机标定(一)--内参标定与程序实现 相机标定(二)--图像坐标与世界坐标转换 相机标定(三)--手眼标定 一.坐标关系 相机中有四个坐标系,分别为world,camera,image,pixel w ...

最新文章

  1. JavaScript原型与原型链(总结篇)
  2. Java中善用通用的枚举对象类实现代码业务的判断
  3. 搭建TFS2008的过程及其注意事项
  4. Windows下Git Bash Here怎么整个文件夹目录上传到代码仓库(不论GitHub、GitLab、Gitee、DevCloud)
  5. 谷歌浏览器实现直接打印效果
  6. 闲鱼发布2020租房报告:每天近万人在闲鱼找室友
  7. 洛谷P1313 计算系数【快速幂+dp】
  8. android的四大组件及使用场景,Android/四大组件/Activity.md · BoraxZYF/AndroidInterview - Gitee.com...
  9. 曾经的那些绝世电脑高手们
  10. 四旋翼飞行器——飞行原理
  11. 牛X的规则引擎urule2
  12. H5标签datalist
  13. 无人机倾斜摄影技术在不动产项目中的实际运用
  14. 16天7000dict
  15. 说说自己工作中的测试流程
  16. 太厉害了!我用 Nginx 提升系统10倍性能
  17. 高并发如何处理,解决方案
  18. Phalloidin——Acti-stain555鬼笔环肽研究
  19. C#圆形卡尺测量程序基于halcon
  20. 【新示例】阿里系行业SaaS,企加云要做IOE的赋能者

热门文章

  1. 好书精读推荐:《苏世民:我的经验与教训》
  2. IOS 新增字体类型
  3. 抖音热搜 API数据接口
  4. Axios封装拦截器
  5. python可以用来写什么_python这么火,到底可以用来做什么?
  6. 学习笔记——12306 自动通过验证码(2)
  7. 妥协型人格分析,妥协型性格的缺点和改善
  8. gb28181简单实现sip信令服务器(java版基于springboot):一、netty创建udp服务器
  9. 8086+DAC0832产生方波、三角波及正弦波波形Proteus仿真
  10. 华硕主板使用nt6 oem loader激活之后重启卡在ASUS LOGO位置无法进入BIOS界面