How to solve this problem when rendering 3D images?

I have three-dimensional image data that I need to render. I was able to render it using 2D fragments using imshow3D , but I would like to see image data in 3D space.

The code I used looks like this (kindly: How to create a rectangular mask at known angles? ), But I can’t say why this isn’t "t:

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

Although the solid panel is not diagonal, as shown in the figure below, I expect the image to be something similar to this:

enter image description here

I don't know exactly what I'm doing wrong here.

+2
source share
1 answer

As for the problem in your code, it seems that you set the points inside the sphere to 1, and then set all the remaining points outside the sphere to 2, and then through the y plane to 3. There is no value 0 in volume in this case, so try to get isosurface if set to 0, it will not find anything.

However, if you prefer to create a “voxelized” Minecraft surface, as in your sample showing the edges of your voxels, then I have one more option for you ...

First, I created a volume dataset, as in your example, except that I omitted the for loop, which sets the values ​​to 2, and instead sets the solid bar to 2.

Then I used the build_voxels function, which I used in several of my 3D projects:

 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 

This function takes a 3D matrix, ideally a logical mask of volume area (s) to create a surface for and returns 4 4-on-N matrices: X/Y/Z matrices for voxel face patches and an index matrix C , which can be used to obtain values ​​from the volume data matrix to use when painting each surface.

Here is the code for visualizing surfaces:

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

And here is the plot:

enter image description here

Please note that the surfaces of the sphere and the rod are colored differently, since they are marked with values ​​1 and 2, respectively, in the volume data Img . These values ​​are extracted from Img using C , and then used as an index in rgbData , which contains red (first row) and yellow (second row) RGB triplets. This will create an N-by-1-by-3 matrix of the polygon color .

+4
source

Source: https://habr.com/ru/post/1215991/


All Articles