STL与Dicom坐标系对应关系(Matlab版)

# STL与Dicom坐标系对应关系(Matlab版)
Dicom是常用的医学影像存储格式,医生及医学影像工作者对此非常熟悉,本文尝试总结STL文件跟Dicom文件间的关系,并附有Matlab实现代码
问题提出
是否曾有过STL的显示与Dicom数据的显示位置不对的情况?如
这里写图片描述
问题分析
此问题主要是STL坐标系与Dicom数据的坐标系不统一导致的。一般来说,Dicom数据保存了影像设备的原点及方向向量,因此,影像浏览器在导入图像数据时会通过该信息把三维图像转换到世界坐标系的真实位置。但是,由于STL文件的生成最初是基于图像坐标系的,所以生成STL时需要把图像坐标系的坐标点转换为世界坐标系。

以下简略介绍Dicom及STL,最后通过matlab代码对其进行关联。
Dicom
网络上很多博主已经总结了Dicom常用的Tag值和冠状面,矢状面和横断面的解释,详情见Tag值三视图

关于Dicom坐标系的详细解释,见Roni的博客,以下为一些中文翻译及总结:
Image Plane Module定义了相对于病人身体的图像方向及每个方向的像素(或体素)间距(mm)。
这里写图片描述

Dicom定义了Reference Coordinates System (RCS),分别为轴状位(Transverse/Axisplane XY)、冠状位(Coronal/Frontal plane XZ)和矢状位(Sagittal plane YZ)。其中X方向是从右到左,
这里写图片描述
Y方向是从前到后,
这里写图片描述
Z方向是从脚到头
这里写图片描述

目前,我们了解了Dicom格式的方向定义,
[R] -Right-沿着X方向递减;
[L] -Left-沿着X方向递增;
[A] -Anterior- 沿着Y方向递减;
[P] - Posterior- 沿着Y方向递增;[F] -Feet-沿着Z方向递减;
[H] - Head- 沿着Z方向递增。
大家可能会问,如果病人躺着拍和俯着拍不是不一样吗?Dicom标准提供patient position(0018,5100)来确定病人被扫描时的状态:
HFP = Head First-Prone(头部前,俯卧).
HFS = Head First-Supine(头部前,仰卧).
FFP = Feet First-Prone(脚部前,俯卧).
FFS = Feet First-Supine(脚部前,仰卧)
HFDR = Head First-Decubitus Right(头部前,右侧俯卧).
HFDL = Head First-Decubitus Left(头部前,左侧俯卧).
FFDR = Feet First-Decubitus Right(脚部前,右侧俯卧).
FFDL = Feet First-Decubitus Left(脚部前,左侧俯卧).
这里写图片描述
STL

一般图像处理都是以图像坐标系进行编辑,即从1(C为0)开始,间隔为1。但是此时获取的STL文件并不能与DICOM数据一一对应,如

通过4*4的旋转矩阵可以使基于图像坐标系的STL旋转平移到目标世界坐标系中,而Dicom的Tag值可以获取旋转矩阵所需的信息,以下为旋转矩阵获取代码:


function [M,R] = TransMatrix(info)
%This function calculates the 4x4 transform matrix from the image
%coordinates to patient coordinates. 
ipp=info.ImagePositionPatient;
iop=info.ImageOrientationPatient;
ps=info.PixelSpacing;
Tipp=[1 0 0 ipp(1); 0 1 0 ipp(2); 0 0 1 ipp(3); 0 0 0 1];
r=iop(1:3);  c=iop(4:6); s=cross(r',c');
R = [r(1) c(1) s(1) 0; r(2) c(2) s(2) 0; r(3) c(3) s(3) 0; 0 0 0 1];
if info.MRAcquisitionType=='3D' % 3D turboflash
    S = [ps(2) 0 0 0; 0 ps(1) 0 0; 0 0 info.SliceThickness 0 ; 0 0 0 1];
else % 2D epi dti
    S = [ps(2) 0 0 0;0 ps(1) 0 0;0 0 info.SpacingBetweenSlices 0;0 0 0 1];
end
T0 = [ 1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1];
M = Tipp * R * S * T0;
end

以下为STLResult为你分割后的模板矩阵,str_DicomInfo为Dicom文件的路径

STL_X = 0:1:(n_NumX-1);
STL_Y = 0:1:(n_NumY-1);
STL_Z = 0:1:(n_NumZ-1);
fv = isosurface(STL_X,STL_Y,STL_Z,STLResult,0.5);
fCols8bit = zeros(size(fv.faces));
fCols8bit(:,1) = 255;
info = dicominfo(str_DicomInfo);    
[M,R] = TransMatrix(info);
n_VerticesNum = size(fv.vertices);
TempData=ones(4,1);
for num=1:n_VerticesNum
    TempData(1:3,1) = (fv.vertices(num,:))';
    TempResult = (M*TempData)';
    fv.vertices(num,:) = TempResult(1,1:3);
end
stlwrite(str_Output,fv,'FaceColor',fCols8bit);

转换结果
经过4*4矩阵变换的结果为:
这里写图片描述

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值