【问题标题】:How do I resolve this issue with 3D image visualization?如何使用 3D 图像可视化解决此问题?
【发布时间】:2017-10-12 10:04:36
【问题描述】:

我有需要可视化的 3D 图像数据。我已经能够使用imshow3D 使用 2D 切片对其进行可视化,但我希望在 3D 空间中查看图像数据。

我使用的代码如下(礼貌:How do i create a rectangular mask at known angles?),但我不知道为什么它不显示:

% create input image
imageSizeX = 120;
imageSizeY = 200;
imageSizeZ = 50

% generate 3D grid
[columnsInImage, rowsInImage, pagesInImage] = meshgrid(1:imageSizeX, 1:imageSizeY, 1:imageSizeZ);

% create the sphere in the image.
centerY  = imageSizeY/2;
centerX  = imageSizeX/2;
centerZ  = imageSizeZ/2;
diameter = 56;
radius   = diameter/2;

sphereVoxels = (rowsInImage - centerY).^2 ...
    + (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2;


% change image from logical to numeric labels.
Img   = double(sphereVoxels);
for ii = 1:numel(Img)
    if Img(ii) == 0
        Img(ii) = 2;  % intermediate phase voxels
    end 
 end



% specify the desired angle
angle = 60;                     

% specify desired pixel height and width of solid
width  = imageSizeX;    
height = imageSizeY;
page   = imageSizeZ;

% Find the row point at which theta will be created
y = centerY - ( radius*cos(angle * pi/180) ) 

% determine top of the solid bar
y0 = max(1, y-height); 

% label everything from y0 to y to be = 3 (solid)
Img(y0:y, 1:width, 1:page)=3;   
% figure, imshow3D(Img);
% axis on;
% grid on;


% display it using an isosurface 
fv = isosurface(Img, 0);
patch(fv,'FaceColor',[0 0 .7],'EdgeColor',[0 0 1]);  title('Binary volume of a sphere');
view(45,45);
axis tight;
grid on;
xlabel('x-axis [pixels]'); ylabel('y-axis [pixels]'); zlabel('z-axis [pixels]')

虽然实心条不是如下图所示的对角线,但我希望图像与此类似:

我不知道我在这里做错了什么。

【问题讨论】:

  • 另外,如果您真的想像示例图像中那样渲染体积(即“体素化”的类似 Minecraft 的视图)而不是使用等值面,我可以为您提供解决方案。
  • 哦,我明白了!谢谢@gnovice,我很高兴有这个解决方案。非常非常感谢您的好意...

标签: matlab image-processing multidimensional-array plot visualization


【解决方案1】:

关于代码中的问题,您似乎将球内的点设置为 1,然后将球外的所有剩余点设置为 2,然后将通过 y 平面的截面设置为 3。没有值在这种情况下,音量为 0,因此尝试获取值为 0 的 isosurface 不会找到任何东西。

但是,如果您希望创建一个“体素化”的类似 Minecraft 的表面,例如在您的示例图像中显示体素的各个方面,那么我可以为您提供另一种选择...

首先,我像您在示例中所做的那样创建了一组体积数据,除了我省略了将值设置为 2 的 for 循环,而是将实心条的值设置为 2。

接下来,我使用了我在几个 3D 项目中使用过的函数 build_voxels

function [X, Y, Z, C] = build_voxels(roiMask)
  maskSize = size(roiMask);

  % Create the ROI surface patches pointing toward -x:
  index = find(diff(padarray(roiMask, [1 0 0], 'pre'), 1, 1) > 0);
  [X1, Y1, Z1, C1] = make_patches([-1 -1 -1 -1], [1 1 -1 -1], [-1 1 1 -1]);

  % Create the ROI surface patches pointing toward +x:
  index = find(diff(padarray(roiMask, [1 0 0], 'post'), 1, 1) < 0);
  [X2, Y2, Z2, C2] = make_patches([1 1 1 1], [-1 -1 1 1], [-1 1 1 -1]);

  % Create the ROI surface patches pointing toward -y:
  index = find(diff(padarray(roiMask, [0 1 0], 'pre'), 1, 2) > 0);
  [X3, Y3, Z3, C3] = make_patches([-1 -1 1 1], [-1 -1 -1 -1], [-1 1 1 -1]);

  % Create the ROI surface patches pointing toward +y:
  index = find(diff(padarray(roiMask, [0 1 0], 'post'), 1, 2) < 0);
  [X4, Y4, Z4, C4] = make_patches([1 1 -1 -1], [1 1 1 1], [-1 1 1 -1]);

  % Create the ROI surface patches pointing toward -z:
  index = find(diff(padarray(roiMask, [0 0 1], 'pre'), 1, 3) > 0);
  [X5, Y5, Z5, C5] = make_patches([1 1 -1 -1], [-1 1 1 -1], [-1 -1 -1 -1]);

  % Create the ROI surface patches pointing toward +z:
  index = find(diff(padarray(roiMask, [0 0 1], 'post'), 1, 3) < 0);
  [X6, Y6, Z6, C6] = make_patches([-1 -1 1 1], [-1 1 1 -1], [1 1 1 1]);

  % Collect patch data:
  X = [X1 X2 X3 X4 X5 X6];
  Y = [Y1 Y2 Y3 Y4 Y5 Y6];
  Z = [Z1 Z2 Z3 Z4 Z5 Z6];
  C = [C1 C2 C3 C4 C5 C6];

  function [Xp, Yp, Zp, Cp] = make_patches(Xo, Yo, Zo)
    [Xp, Yp, Zp] = ind2sub(maskSize, index);
    Xp = bsxfun(@plus, Xp, Xo./2).';
    Yp = bsxfun(@plus, Yp, Yo./2).';
    Zp = bsxfun(@plus, Zp, Zo./2).';
    Cp = index(:).';
  end
end

此函数接受 3D 矩阵,理想情况下是要为其创建表面的体积区域的逻辑掩码,并返回 4 个 4×N 矩阵:X/Y/Z 用于体素面片和索引矩阵的矩阵C 可用于从体积数据矩阵中获取值,用于为每个表面着色。

这是渲染表面的代码:

[X, Y, Z, C] = build_voxels(Img > 0);
rgbData = reshape([1 0 0; 1 1 0], [2 1 3]);
hSurface = patch(X, Y, Z, rgbData(Img(C), :, :), ...
                 'AmbientStrength', 0.5, ...
                 'BackFaceLighting', 'unlit', ...
                 'EdgeColor', 'none', ...
                 'FaceLighting', 'flat');
axis equal;
axis tight;
view(45, 45);
grid on;
xlabel('x-axis (voxels)');
ylabel('y-axis (voxels)');
zlabel('z-axis (voxels)');
light('Position', get(gca, 'CameraPosition'), 'Style', 'local');

剧情如下:

请注意,球体和条形表面的颜色不同,因为它们在体积数据Img 中分别标有值 1 和 2。这些值是使用CImg 中提取的,然后用作rgbData 的索引,其中包含红色(第一行)和黄色(第二行)RGB 三元组。这将创建一个 polygon face colors 的 N×1×3 矩阵。

【讨论】:

  • 哇!这正是我所需要的。非常感谢@gnovice!同时,我不明白如何更改parula颜色图(请原谅我的无知)。我不介意让球体变成红色。再次感谢!
  • @User1333:我编辑了我的答案以展示如何控制颜色图。
  • 很抱歉打扰你,但如果我能问你最后一件事,你能不能帮我绘制这张图片,使 z 轴指向页面(即图像坐标系)?
  • @User1333:由view 函数控制。第一个参数是方位角(XY 平面中的旋转),第二个参数是仰角。 90 度的仰角将从上方向下看(正 z 轴指向屏幕外)。
  • 我知道我发布这个已经有一段时间了,但我仍然需要一些帮助。我试图使图像透明,这有效……只是红色和黄色体素都变成了单一颜色。请问,除了透明之外,我如何使它们具有不同的颜色?感谢您的帮助。
猜你喜欢
  • 2021-01-03
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
  • 2020-08-24
  • 1970-01-01
  • 2020-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多