利用DICOM文件实现2D与3D体素坐标之间的转换
在此感谢Manjunath KN的回答,参考链接如下:https://www.researchgate.net/post/How_to_create_a_simple_project_to_convert_DICOM_images_to_3d_images
2D to 3D
1.需要的信息
将2D坐标转换为3D坐标需要以下DICOM信息2D:
- input point (x,y):原始的2D坐标
- Image position patient (0020, 0032):ImageOrientation
- Pixel spacing (0028, 0030):PixelSpacing
- Row vector and column vectors (0020,0037):ImageOrientation
DICOM 提取示例代码如下:
def getinfo(img_file):RefDs = dicomio.read_file(img_file)# print(dir(RefDs)) #查看dicom文件的属性img_array = RefDs.pixel_array# indexes are z,y,x ImagePosition =np.array(RefDs.ImagePositionPatient)ImageOrientation=np.array(RefDs.ImageOrientationPatient)PixelSpacing =RefDs.PixelSpacingSliceThickness=RefDs.SliceThicknessImageOrientationX=ImageOrientation[0:3]ImageOrientationY=ImageOrientation[3:6]#z轴(X与Y的叉积)normalvector=np.cross(ImageOrientationX,ImageOrientationY)return img_array,normalvector,ImagePosition,PixelSpacing,ImageOrientationX,ImageOrientationY
2.转换过程
Voxel (x, y, z) = Image Plane Position + Row change in X + column change in Y
Where Row change in X = Row vector * Pixel size in X direction * 2D Point location in X direction
Column change in Y = Column vector * Pixel size in Y direction * 2D Point location in Y direction
示例:
Image position patient = (100,100,50) #ImagePositionPatient
row vector=(1,0,0) #ImageOrientationX
column vector=(0,1,0) #ImageOrientationY
pixel size=(0.5,0.5) #PixelSpacing
2D point=(5,6)
Voxel (x,y,z) = (100,100, 50) + (1,0,0) * 0.5 *5 + (0,1,0)0.5 6 = (100,100,50) + (2.5,0,0)+ (0,3,0) = (102.5, 103, 50)
3.将2d平面转换到3d空间原理
这里主要是解释下文代码中 “建立方程组:dx(x-a)+dy(y-b)+dz(z-c)=0”的原理:
(1)dx(x-a)+dy(y-b)+dz(z-c)=0
我们在高中学过空间平面的几种表达方式,比如有点法式、一般式等等。其中点法式最常用的就是A(x-x0)+B(y-y0)+C(z-z0)=0。这里的含义很好理解,假设向量vN=(A,B,C)是平面的法向量,然后取平面任一点p0=(x0,y0,z0)【带入上面式子等于零,说明该点在平面上】。所谓的空间平面,就是任一点pX与点p0链接的直线(pX,p0)与法向量vN内积和等于零。也就是A(x-x0)+B(y-y0)+C(z-z0)=0。这里做了简化,即写成dx(x-a)+dy(y-a)+dz(z-a)=0的意思是直接取(dx,dy,dz)就是法向量的x,y,z三个方向的分量。相当于是吧法向量(A,B,C)进行了归一化处理。
(2)ImageOrientationX即X轴的方向,ImageOrientationY即Y轴方向
图像平面的长,宽方向的方向余弦向量其实就是归一化后的方向向量,叉乘获得的就是平面的法向量,每个分量就是dx,dy,dz。
(3)关于dicon中的左边系可参考博客
https://blog.csdn.net/zssureqh/article/details/61636150
4.两个2d平面投影到3d空间并求得交线
def getIntersection(f1=None,f2=None,path=None):#get infoimg_array1,normalvector1, ImagePosition1,PixelSpacing1,ImageOrientationX1,ImageOrientationY1= getinfo(f1)img_array2,normalvector2, ImagePosition2,PixelSpacing2,ImageOrientationX2,ImageOrientationY2 = getinfo(f2)# 设置 并设置符号变量sp.init_printing(use_unicode=True)InteractiveShell.ast_node_interactivity = 'all'x, y, z = symbols('x, y, z')#建立方程组#dx(x-a)+dy(y-b)+dz(z-c)=0z1=[normalvector1[0] * (x - ImagePosition1[0]) + normalvector1[1] * (y - ImagePosition1[1]) ] /normalvector1[2] + ImagePosition1[2]z2 = [normalvector2[0] * (x - ImagePosition2[0]) + normalvector2[1] * (y - ImagePosition2[1])] / normalvector2[2] + \ImagePosition2[2]eq=[normalvector1[0] * (x - ImagePosition1[0]) + normalvector1[1] * (y - ImagePosition1[1]) + normalvector1[2] * (z - ImagePosition1[2]),\normalvector2[0] * (x - ImagePosition2[0]) + normalvector2[1] * (y - ImagePosition2[1]) + normalvector2[2] * (z - ImagePosition2[2])]#解方程s = list(linsolve(eq, [x, y]))# show_3d(normalvector1, ImagePosition1,normalvector2,ImagePosition2,s)
在3d空间展示平面
def show_3d(normalvector1,ImagePosition1,normalvector2,ImagePosition2,s):# 3d空间交线的表达式x1_3d = s[0][0]y1_3d = s[0][1]x, y, z = symbols('x, y, z')fig = plt.figure()ax = Axes3D(fig)# 生成x,y的网格数据X = np.arange(-256, 256, 1)# Y = np.arange(-4, 4, 0.25)Y = np.arange(-256, 256, 1)X, Y = np.meshgrid(X, Y)Z1=(normalvector1[0]* (X - ImagePosition1[0]) + normalvector1[1]* (Y - ImagePosition1[1]))/ normalvector1[2] + ImagePosition1[2]Z2 = (normalvector2[0] * (X - ImagePosition2[0]) + normalvector2[1] * (Y - ImagePosition2[1])) / normalvector2[2] + ImagePosition2[2]# show linea1,a2=x1_3d.coeff(z),y1_3d.coeff(z)b1,b2=x1_3d.coeff(z,0),y1_3d.coeff(z,0)zi = np.linspace(-250, 256, 100)xi=a1*zi+b1yi=a2*zi+b2ax.plot3D(xi,yi,zi)ax.plot_surface(X, Y, Z1, rstride=1, cstride=1, color='r')#cmap='rainbow'ax.plot_surface(X, Y, Z2, rstride=1, cstride=1, color="g")plt.show()
3D to 2D
1.原理
Conversion from 3D to 2D
Difference = Voxel – Image plane Pos;
Difference_in_X = Difference.Innerproduct(Row vector)
Difference_in_Y = Difference.Innerproduct(Col vector);
2D Point = (Difference_in_X/pixel size in X, Differnce_in_Y/pixel size in Y)
这是所涉及的基本逻辑。上述方程组也可以通过矩阵乘法来实现。请参阅第410页,DICOM,章节PS 3.3,2011年版本,或者在文件http://dicom.nema.org/medical/dicom/current/output/pdf/part03.pdf中搜索标签0020,0037
2.代码
(1)3d 空间的交线投影到对应的2D平面
def TO2D(s,ImagePosition,ImageOrientationX,ImageOrientationY,PixelSpacing):# s为3d空间交线的表达式x, y, z = symbols('x, y, z')x1_3d = s[0][0]y1_3d = s[0][1]pos=[x1_3d,y1_3d,z]differ=pos-ImagePositiondiffer_x=np.dot(differ,ImageOrientationX)differ_y=np.dot(differ,ImageOrientationY)pos_2d=[differ_x/PixelSpacing[0],differ_y/PixelSpacing[1]]return pos_2d
利用DICOM文件实现2D与3D体素坐标之间的转换相关推荐
- 动态文件、2d、3d、Html设置电脑桌面背景【超实用】
LivelyWallpaper是一个非常棒的电脑桌面背景设置软件,可用url.html.图片.2d.3d等文件设置为win10桌面背景,且cpu占用极低. 一.下载: 1.https://www.mi ...
- 闪存颗粒-2D和3D闪存之间的区别和联系
转载:http://ssd.zol.com.cn/625/6254456.html 首先是2D NAND,我们知道在数学和物理领域,2D/3D都是指的方向,都是指的坐标轴,"2D" ...
- 自学Python第二十二天- Django框架(三) AJAX、文件上传、POST 请求类型之间的转换、多APP开发、iframe、验证码、分页器、类视图、中间件、信号、日志、缓存、celery异步
Django官方文档 django 使用 AJAX django 项目中也可以使用 ajax 技术 前端 前端和其他 web 框架一样,需要注意的是,django 接收 POST 请求时,需要 csr ...
- react中使用jszip获取压缩包里文件的方法、Blob与Flie之间的转换
react中jszip获取压缩包里的文件方法: // react里通过npm install jszip安装 import JSZip from 'jszip'const zip = new JSZi ...
- CSS3之2D与3D转换
在CSS3中新增了很多关于2D和3D转换的标准,它允许将页面元素在2D和3D空间内进行移动.缩放.旋转.倾斜等.所谓的2D转换,指的是元素可以在平面内进行位置或形状的转换,而3D转换指的是元素可以在三 ...
- 2D转3D技术的优势
从传统电影出现到目前为止,已经积累了大量的2D的电影,2D转3D可以让2D影片绽放3D的魅力.在3D电影的制作中,由于拍摄上物理的限制,很多特殊的镜头是拍摄不出正确的3D效果,和得不到需要的3D艺术效 ...
- 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——2.3节简析Android安装文件...
本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第2章,第2.3节简析Android安装文件,作者 王石磊 , 吴峥,更多章节内容可以访问 ...
- 利用Python绘制 3D 体素色温图
简 介: 测试了Matplotlib中的 体素绘制函数 voxels() ,但是无论是在 AI Studio中执行,还是直接在本地执行,都会出了错误.也就是无法通过 gca(projection='3 ...
- 【WPF学习手记】利用fo-dicom读取DICOM文件
利用开源库 fo-dicom 读取 DICOM 文件基本操作. 读取DICOM信息 原始数据经过窗宽.窗位校正后显示成图. private void Button_Click1(object send ...
最新文章
- 2022-2028年中国椎间孔镜行业市场研究及前瞻分析报告
- ThreadLocal 简介
- SpringBoot集成全局异常处理
- 银行柜员网申计算机水平要求高吗,银行网申没通过,是因为你水平差吗?
- 11g新特性-自动sql调优(Automatic SQL Tuning)
- 文末送书 | 数据分析简单入门
- 【job】面试中常见的笔试梳理
- 金蝶K3退出远程桌面后,客户端无法登陆
- paypalsdk集成php,php核心paypal sdk
- linux 文件名加粗,konsole与用粗体绘制强调色
- 解决Linux系统下字体没有宋体和黑体问题
- h5在线游戏制作开发:h5模板打地鼠小游戏怎么制作?
- 英特尔cpu发布时间表_英特尔10代桌面cpu上市时间(英特尔10代发售时间)
- 页面中设置IE浏览器的文档模式
- 远程工具MobaXterm安装和使用教程
- sim卡没坏但苹果手机无服务_工信部为啥要喊你设置SIM卡密码?如何设置(安卓苹果都有了)|工信部|手机|安卓|安卓手机|iphone...
- 快速学习一门新技术的工作原理(十步学习法来自软技能)
- galera-mariadb集群
- “已连接,但无法访问互联网”开机后wifi有感叹号, 时间无法同步解决办法
- 【ubuntu】htop命令详解
热门文章
- Rose Blumki
- (附源码)springboot社区养老医疗服务平台 毕业设计 041148
- Allure报告的安装及环境变量的配置和在pytest中调用
- 3ds Max发生闪退怎么办?
- 电脑ctrl和ALT经常键自动按住--答案是QQ2012的Bug
- 解决npm ERR! Unexpected end of JSON input while parsing near的方法汇总
- OSPF中双ASBR重发布5类LSA问题
- wordpress主题转html,WordPress主题的 HTML静态页面模板制作教程
- 每日一面 - java里的wait()和sleep()的区别有哪些?
- JDBC实现多条件查询万能解决思路