我是 dicom 开发组的初学者。我需要在 dicom image 上创建一个定位器图像行。那么,有没有什么好主意。任何极客。
1 回答
David Brabant 已经为您指明了正确的方向(如果您想使用 DICOM,您绝对应该阅读并珍惜dclunie 的医学图像常见问题解答)。让我们看看我是否可以详细说明它并使您更容易实现。
我假设您有一个工具/库来从 DICOM 文件(Offis 的 DCMTK?)中提取标签。为了举例说明,我将参考 CT 扫描(许多切片,即许多图像)和侦察图像,您希望在其上显示定位线。每个 DICOM 图像,包括您的 CT 切片和您的侦察,都包含有关它们在空间中位置的完整信息,在这两个标签中:
Group,Elem VR Value Name of the tag --------------------------------------------------------------------- (0020,0032) DS [-249.51172\-417.51172\-821] # ImagePositionPatient X0 Y0 Z0 (0020,0037) DS [1\0\0\0\1\0] # ImageOrientationPatient A B C D E F
ImagePositionPatient 具有以毫米为单位的第一个传输像素的全局坐标(要清楚的是左上角像素),表示为 (x,y,z)。我将它们标记为 X0、Y0、Z0。ImageOrientationPatient 包含两个向量,都是三个分量,指定图像的第一行像素和第一列像素的方向余弦。理解方向余弦并没有什么坏处(参见例如http://mathworld.wolfram.com/DirectionCosine.html),但是 dclunie 建议的方法直接与它们一起使用,所以现在让我们说它们为您提供空间中的方向图像平面。我将它们标记为 AF 以使公式更容易。
现在,在 dclunie 给出的代码中(我相信它的目的是 C,但它非常简单,它应该和 Java、C#、awk、Vala、Octave 等一样工作)约定如下:
scr_* = 指源图像,即CT切片
dst_* = 指目标图像,即侦察兵
*_pos_x, *_pos_y, *_pos_z = 上面的 X0, Y0, Z0
*_row_dircos_x, *_row_dircos_y, *_row_dircos_z = 上面的 A, B, C
*_col_dircos_x、*_col_dircos_y、*_col_dircos_z = 上面的 D、E、F
设置正确的值后,只需应用这些:
dst_nrm_dircos_x = dst_row_dircos_y * dst_col_dircos_z
- dst_row_dircos_z * dst_col_dircos_y;
dst_nrm_dircos_y = dst_row_dircos_z * dst_col_dircos_x
- dst_row_dircos_x * dst_col_dircos_z;
dst_nrm_dircos_z = dst_row_dircos_x * dst_col_dircos_y
- dst_row_dircos_y * dst_col_dircos_x;
src_pos_x -= dst_pos_x;
src_pos_y -= dst_pos_y;
src_pos_z -= dst_pos_z;
dst_pos_x = dst_row_dircos_x * src_pos_x
+ dst_row_dircos_y * src_pos_y
+ dst_row_dircos_z * src_pos_z;
dst_pos_y = dst_col_dircos_x * src_pos_x
+ dst_col_dircos_y * src_pos_y
+ dst_col_dircos_z * src_pos_z;
dst_pos_z = dst_nrm_dircos_x * src_pos_x
+ dst_nrm_dircos_y * src_pos_y
+ dst_nrm_dircos_z * src_pos_z;
或者,如果你有一些花哨的矩阵类,你可以构建这个矩阵并将它与你的点坐标相乘。
[ dst_row_dircos_x dst_row_dircos_y dst_row_dircos_z -dst_pos_x ] M = [ dst_col_dircos_x dst_col_dircos_y dst_col_dircos_z -dst_pos_y ] [ dst_nrm_dircos_x dst_nrm_dircos_y dst_nrm_dircos_z -dst_pos_z ] [ 0 0 0 1 ]
那将是这样的:
Scout_Point(x,y,z,1) = M * CT_Point(x,y,z,1)
说了这么多,我们应该转换 CT 的哪些点以在侦察器上创建一条线?同样对于这个 dclunie 已经提出了一个通用的解决方案:
“我的方法是投影作为源图像边界框的正方形(即连接切片的 TLHC、TRHC、BRHC 和 BLHC 的线)。 ”
如果您投影 CT 切片的四个角点,您将有一条垂直于侦察线的 CT 切片线,以及一条不垂直切片的梯形。现在,如果您的 CT 切片与坐标轴对齐(即 ImageOrientationPatient = [1\0\0\0\1\0]),那么这四个点是微不足道的。您使用行/列数和沿 x/y 方向的像素距离计算图像的宽度/高度(以 mm 为单位),并适当地总结。如果你想实现通用案例,那么你需要一点三角函数......或者可能不需要。如果您还没有阅读方向余弦的定义,也许是时候阅读了。
我会努力让你走上正轨。例如,在 TRHC 上工作,您知道体素在图像平面中的位置:
# Pixel location of the TRHC x_pixel = number_of_columns-1 # Counting from 0 y_pixel = 0 z_pixel = 0 # We're on a plane!
DICOM 中的像素距离值是指图像平面,因此您可以简单地将 x 和 y 乘以这些值,使其位置以 mm 为单位,而 z 为 0(像素和 mm)。我说的是这些价值观:
(0028,0011) US 512 # 2, 1 Columns (0028,0010) US 512 # 2, 1 Rows (0028,0030) DS [0.9765625\0.9765625] # 20, 2 PixelSpacing
上面的矩阵 M 是从全局坐标到图像坐标的通用转换,具有可用的方向余弦。您现在需要的是在源图像(CT 切片)上执行逆向工作(图像到全局)的东西。我会让你去挖掘几何书籍以确定,但我认为它应该是这样的(旋转部分被转置,平移没有符号变化,当然我们使用 src_* 值):
[src_row_dircos_x src_col_dircos_x src_nrm_dircos_x src_pos_x ] M2 = [src_row_dircos_y src_col_dircos_y src_nrm_dircos_y src_pos_y ] [src_row_dircos_z src_col_dircos_z src_nrm_dircos_z src_pos_z ] [0 0 0 1 ]
将 CT 切片中的点(例如四个角)转换为毫米,然后应用 M2 使它们位于全局坐标中。然后您可以将它们提供给 dclunie 报告的程序。在使用它之前交叉检查我的数学,例如用于患者诊断!;-)
希望这有助于更好地理解 dclunie 的方法。干杯