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!