How to draw oblique hemisphere along a certain volume?
我想做什么:
制作一个空的 3D 图像(在本例中为 .dcm),图像方向为
0,1,0;
0,0,1]
在这张图片中,我插入了一个倾斜的轨迹,它基本上代表了一个长方体。现在我希望在这个长方体中插入一个空心半球(所有白色像素的长方体 - 恒定值,半球可以是不可微的),以便它沿着轨迹的轴对齐。
我得到了什么
所以我使用了球体的通用公式:
1 2 3 | x = x0 + r*cos(theta)*sin(alpha) y = y0 + r*sin(theta)*sin(alpha) z = z0 + r*cos(alpha) |
其中,0 <= theta <= 2 * pi,0 <= alpha <= pi / 2,对于半球。
我试图实现的目标
所以首先我想只得到图像坐标系和轨迹坐标系之间的旋转矩阵,并将球体上的所有点与它相乘。这并没有给我想要的结果,因为旋转的球体被缩放和平移。当我自己检查点时,我不明白为什么会发生这种情况。
然后我想为什么不从一个球体中制作一个半球,该球体被一个平行于轨迹坐标系的 y,z 平面的平面切割。为此,我计算了图像的 x、y 和 z 轴之间的angular与轨迹的angular。然后,我开始获取 theta_rotated 和 alpha_rotated 的半球坐标。这也不起作用,因为我得到了一个相当奇怪的球体,而不是半球。
这是没有任何转换
这是angular变换(第二次尝试)
供参考,
轨迹坐标系:
-0.7049, 0.613244, 0.3892;
-0.5273, -0.787537, 0.342;];
给出angular:
x_axis angular 2.06508 pi
y_axis angular 2.2319 pi
z_axis angular 1.22175 pi
生成长方体的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | Vector3d getTrajectoryPoints(std::vector<Vector3d> &trajectoryPoints, Vector3d &target1, Vector3d &tangent1){ double distanceFromTarget = 10; int targetShift = 4; target -= z_vector; target -= (tangent * targetShift); Vector3d vector_x = -tangent; y_vector = z_vector.cross(vector_x); target -= y_vector; Vector3d start = target - vector_x * distanceFromTarget; std::cout <<"target =" << target <<"start =" << start << std::endl; std::cout <<"x" << vector_x <<" y" << y_vector <<" z" << z_vector << std::endl; double height = 0.4; while (height <= 1.6) { double width = 0.4; while (width <= 1.6){ distanceFromTarget = 10; while (distanceFromTarget >= 0){ Vector3d point = target + tangent * distanceFromTarget; //std::cout << (point + (z_vector*height) - (y_vector * width)) << std::endl; trajectoryPoints.push_back(point + (z_vector * height) + (y_vector * width)); distanceFromTarget -= 0.09; } width += 0.09; } height += 0.09; } } |
相对于体素间距增加的高度和宽度。
你们知道如何实现这一目标吗?我做错了什么?如果您需要任何其他信息,请告诉我。
编辑 1
在@Dzenan 的回答之后,我尝试了以下操作:
目标 = { -14.0783, -109.8260, -136.2490 }, 切线 = { 0.4744, 0.7049, 0.5273 };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | typedef itk::Euler3DTransform<double> TransformType; TransformType::Pointer transform = TransformType::New(); double centerForTransformation[3]; const double pi = std::acos(-1); try{ transform->SetRotation(2.0658*pi, 1.22175*pi, 2.2319*pi); // transform->SetMatrix(transformMatrix); } catch (itk::ExceptionObject &excp){ std::cout <<"Exception caught !" << excp << std::endl; transform->SetIdentity(); } transform->SetCenter(centerForTransformation); |
然后我遍历半球中的所有点并使用,
虽然,我更愿意给出等于轨迹坐标系(上面提到的)的矩阵,但矩阵不是正交的,itk 不会接受它。必须说我使用了相同的矩阵来重新采样这个图像并提取长方体,这很好。因此,我找到了 x_image - x_trajectory、y_image - y_trajectory 和 z_image - z_trajectory 之间的angular并使用
编辑 2
我试图在没有实际使用极坐标的情况下获得球体坐标。在与@jodag 讨论之后,这就是我想出的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Vector3d center = { -14.0783, -109.8260, -136.2490 }; height = 0.4; while (height <= 1.6) { double width = 0.4; while (width <= 1.6){ distanceFromTarget = 5; while (distanceFromTarget >= 0){ // Make sure the point lies along the cuboid direction vectors Vector3d point = center + tangent * distanceFromTarget + (z_vector * height) + (y_vector * width); double x = std::sqrt((point[0] - center[0]) * (point[0] - center[0]) + (point[1] - center[1]) * (point[1] - center[1]) + (point[2] - center[2]) * (point[2] - center[2])); if ((x <= 0.5) && (point[2] >= -136.2490 )) orientation.push_back(point); distanceFromTarget -= 0.09; } width += 0.09; } height += 0.09; } |
但这似乎也不起作用。
这是输出
您可以在某个物理空间中生成您的半球,然后使用例如转换(平移和旋转)它RigidTransform\\ 的 TransformPoint 方法。然后在 itk::Image 中使用 TransformPhysicalPointToIndex 方法。最后,使用 SetPixel 方法改变强度。使用这种方法,您必须控制半球的分辨率以完全覆盖图像中的所有体素。
另一种方法是构建一个新图像,您可以在其中创建半球,然后使用重采样过滤器在任意图像中创建半球的转换版本。
我对你的第一个图有点困惑,因为显示的点似乎没有在图像坐标中定义。我在下面发布的示例假定体素必须是图像坐标系的一部分。
下面的代码通过逆变换将图像空间中的体素坐标变换到轨迹空间。然后它光栅化一个以 0,0,0 为中心的 2x2x2 立方体和一个沿 xy 轴切片的半径为 0.9 的半球。
与其在评论中继续进行长时间的讨论,我决定发布此内容。如果您正在寻找不同的东西,请发表评论。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | % define trajectory coordinate matrix R = [-0.4744, -0.0358506, -0.8553; -0.7049, 0.613244, 0.3892; -0.5273, -0.787537, 0.342] % initialize 50x50x50 3d image [x,y,z] = meshgrid(linspace(-2,2,50)); sz = size(x); x = reshape(x,1,[]); y = reshape(y,1,[]); z = reshape(z,1,[]); r = ones(size(x)); g = ones(size(x)); b = ones(size(x)); blue = [0,1,0]; green = [0,0,1]; % transform image coordinates to trajectory coordinates vtraj = R\\[x;y;z]; xtraj = vtraj(1,:); ytraj = vtraj(2,:); ztraj = vtraj(3,:); % rasterize 2x2x2 cube in trajectory coordinates idx = (xtraj <= 1 & xtraj >= -1 & ytraj <= 1 & ytraj >= -1 & ztraj <= 1 & ztraj >= -1); r(idx) = blue(1); g(idx) = blue(2); b(idx) = blue(3); % rasterize radius 0.9 hemisphere in trajectory coordinates idx = (sqrt(xtraj.^2 + ytraj.^2 + ztraj.^2) <= 0.9) & (ztraj >= 0); r(idx) = green(1); g(idx) = green(2); b(idx) = green(3); % plot just the blue and green voxels green_idx = (r == green(1) & g == green(2) & b == green(3)); blue_idx = (r == blue(1) & g == blue(2) & b == blue(3)); figure(1); clf(1); plot3(x(green_idx),y(green_idx),z(green_idx),' *g') hold('on'); plot3(x(blue_idx),y(blue_idx),z(blue_idx),' *b') axis([1,100,1,100,1,100]); axis('equal'); axis('vis3d'); |