如何沿一定体积绘制倾斜半球?

时间:2017-08-01 17:29:59

标签: c++ matlab 3d itk

我想做什么

制作一个空的3D图像(在这种情况下为.dcm),图像方向为 [1,0,0; 0,1,0; 0,0,1]。 在这张图片中,我插入了一个倾斜的轨迹,它基本上代表了一个长方体。现在我希望在这个长方体中插入一个空心半球(长方形,所有白色像素 - 恒定值,半球可以是任何可分辨的),以便它沿着轨迹轴对齐。

我得到了什么

所以我使用了球体的通用公式:

x = x0 + r*cos(theta)*sin(alpha)
y = y0 + r*sin(theta)*sin(alpha)
z = z0 + r*cos(alpha)

其中,0 <=θ<= 2 * pi,0 <=α<= pi / 2,对于半球。

我试图实现这一目标

  1. 首先,我想在图像坐标系和轨迹坐标系之间得到旋转矩阵,然后将球体上的所有点与它相乘。当旋转的球体被缩放和翻译时,这并没有给我想要的结果。我不知道为什么会发生这种情况,因为我自己检查了这一点。

  2. 然后我想为什么不在球体外面制作半球,球体由平行于轨迹坐标系的y,z平面的平面切割。为此,我计算了图像的x,y和z轴与轨迹的角度。然后,我开始为theta_rotated和alpha_rotated获得半球坐标。这不是一个半球,而是一个相当奇怪的领域。

  3. Without any transformations 这没有任何转换

    Angle transformation 这是角度变换(第二次尝试)

    供参考,

    轨迹坐标系:

    [-0.4744, -0.0358506, -0.8553; -0.7049, 0.613244, 0.3892; -0.5273, -0.787537, 0.342;];

    给角度:

    x_axis angle 2.06508 pi y_axis角度2.2319 pi z_axis角度1.22175 pi

    生成长方体的代码

    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回答之后,我尝试了以下内容:

    target = { - 14.0783,-109.8260,-136.2490},tangent = {0.4744,0.7049,0.5273};

    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);
    

    然后我循环遍历半球中的所有点并使用

    转换它们

    point = transform->TransformPoint(point);

    虽然,我更喜欢给出等于轨迹坐标系(上面提到的)的矩阵,但是矩阵不是正交的,并且它不会接受它。必须说我使用相同的矩阵重新采样这个图像并提取长方体,这很好。从那里,我找到了x_image - x_trajectory,y_image - y_trajectory和z_image - z_trajectory之间的角度,而使用了SetRotation,这给了我以下结果(仍然不正确): sphere transformed

    编辑2

    我试图在没有实际使用极坐标的情况下获得球体坐标。在与@jodag讨论后,这就是我想出的:

    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;
        }
    

    但这似乎也无效。

    这是输出 SPhere

2 个答案:

答案 0 :(得分:1)

我对你的第一个情节有点困惑,因为看起来所显示的点没有在图像坐标中定义。我在下面发布的示例假定体素必须是图像坐标系的一部分。

下面的代码通过使用逆变换将图像空间中的体素坐标变换为轨迹空间。然后栅格化一个以0,0,0为中心的2x2x2立方体和沿xy轴切割的0.9半径半球。

我没有在评论中继续进行长时间的讨论,而是决定发布此内容。如果您正在寻找不同的东西,请发表评论。

% 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');

enter image description here

答案 1 :(得分:1)

您可以在某个物理空间中生成半球,然后使用例如变换它(平移和旋转)。 RigidTransformTransformPoint方法。然后在itk :: Image中使用TransformPhysicalPointToIndex方法。最后,使用SetPixel方法更改强度。使用此方法,您必须控制半球的分辨率,以完全覆盖图像中的所有体素。

替代方法是构建一个新的图像,在其中创建半球,然后使用resample滤镜在任意图像中创建半球的变换版本。