Troubles With Image Resizing
10 次查看(过去 30 天)
显示 更早的评论
Hello! I have a slice of a .nii file (essentially a 3D array) I'd like to print out. However, the dimensions of a voxel (a 3D pixel, so basically a cube) aren't exactly 1mm x 1mm x 1mm. They're around 1.2mm x 1.1mm x 1.1mm.
I took a slice of the 3D array, so it's just a 2D image. So, the dimensions of each pixel are ~1.2mm x 1.1mm. I'd like to resize the image such that one pixel is equal to one element of the array is equal to one mm. In theory, it doesn't seem too difficult. But I just can't figure this out.
Here's my code so far:
clear
clc
close all
% Load NIfTI image
info = niftiinfo('index_image.nii');
brain = niftiread(info);
% Extract a slice from the NIfTI image
slice = brain(:, :, 128);
% Create figure
hFig = figure;
% Display the slice with pixel-to-mm scaling
imagesc(slice);
axis off;
axis equal;
colormap(gray)
% Set figure size so that 1 pixel corresponds to 1mm on the printed figure
set(hFig, 'Units', 'centimeters', 'Position', [0 0 24 17.6]);
movegui(hFig, 'center');
% Set properties to control the output size
set(hFig, 'PaperUnits', 'centimeters');
set(hFig, 'PaperPosition', [0 0 24 17.6]);
set(hFig, 'PaperOrientation', 'landscape');
% Export to PDF and open file
print(hFig, '-dpdf', '-r0', 'out.pdf');
open('out.pdf');
The reason why use 24 and 17.6 is because my .nii file is 176 x 240 x 256 elements. I'd honestly like the code to work regardless of the size of the array, but even hard coding it into MATLAB isn't working. The code is compiling just fine, but the figure in the generated PDF doesn't have the dimensions I'd like it to have.
Would anyone be able to provide some insights? Thank you!
0 个评论
采纳的回答
Cris LaPierre
2024-5-16
编辑:Cris LaPierre
2024-5-16
If the Medical Imaging Toolbox is included in your license, I suggest using extractSlice to get the voxel information for your slice. The syntax is [X,position,spacings] = extractSlice(medVol,slice,direction)
imshow assumes equal spacing in all directions. When that is not the case, use the XData and YData inputs to specify the real world size of your image. Keep in mind that the first dimension of your array corresponds to Y, and the 2nd corresponds to X.
This code would display the image correctly.
brain = medicalVolume(info);
[img,position,spacings] = extractSlice(brain,128,'transverse') % replace direction accordingly
xMax = size(img, 2)*spacing(2);
yMax = size(img, 1)*spacing(1);
imshow(img, [], XData = [0 xMax], YData = [0 yMax])
Of course, if you don't have the Medical Imaging Toolbox, you could adapt the imshow code accordingly and still get the desired result.
7 个评论
Cris LaPierre
2024-5-17
编辑:Cris LaPierre
2024-5-17
unzip('anat.nii.zip')
brain = niftiread('anat.nii.gz');
info = niftiinfo('anat.nii.gz')
img = squeeze(brain(120,:,:));
spacing = info.PixelDimensions(2:3)
tiledlayout(1,2)
nexttile
imshow(img,[])
nexttile
xMax = size(img,2)*spacing(2);
yMax = size(img,1)*spacing(1);
imshow(img, [], XData = [0 xMax], YData = [0 yMax])
Now recreate the image using imwarp. I can't use the medical imaging toolbox here, so here is the same image using the older approach you were attempting. I manually determined the corresponding slice number in the warped array.
tform = info.Transform;
newBrain = imwarp(brain,tform);
newimg = squeeze(newBrain(:,:,128));
newimg = permute(newimg,[2 1]);
figure
tiledlayout(1,2)
nexttile
imshow(img,[])
nexttile
imshow(newimg,[])
axis xy
The permute is because, in MATLAB, the first dimension of the image array corresponds to Y and the sencond dimention to X. Additionally, the Y axis is reversed in image axes, so axis xy changes that so the image is displayed as expected.
When the volume is warped to real-world coordinates, the dimensions get rearranged, which is why sagittal is now the 3rd dimension instead of the first. As a sanity check, compare the image sizes
% original - real-world size
newSliceNums = ceil(info.PixelDimensions.*info.ImageSize)
% warped - transformed to a 1x1x1 grid
size(newBrain)
When using the Medical Imaging Toolbox, this would be the code
b = medicalVolume("anat.nii.gz");
[i,~,spacing] = extractSlice(b,120,'sagittal')
tiledlayout(1,2)
nexttile
imshow(i,[])
nexttile
xMax = size(i,2)*spacing(2);
yMax = size(i,1)*spacing(1);
imshow(i, [], XData = [0 xMax], YData = [0 yMax])
T = intrinsicToWorldMapping(b.VolumeGeometry)
bwarp = imwarp(b.Voxels,T);
newimg = squeeze(bwarp(:,128,:));
newimg = permute(newimg,[2 1]);
figure
tiledlayout(1,2)
nexttile
imshow(img,[])
nexttile
imshow(newimg,[])
axis xy
更多回答(1 个)
Image Analyst
2024-5-17
Maybe use interpn to resample the array along the "longer pixel" direction to have more samples, like the number of samples it would have if it were 1 mm instead of 1.2 mm.
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Lighting, Transparency, and Shading 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!