[Info Need] How resize 3D volumetric data?

username: Innat
cooked: <p>For 3D volumetric data, how we can resample (upsampling and downsampling) in pytorch?</p>
<p>For example:</p>
<pre><code class="lang-auto">[ format: (bs, h, w, depth, channel) ]
original_input = (None, 256, 256, 40, 3)

upsample_output = (None, 512, 512, 80, 3)
dnsample_output = (None, 128, 128, 20, 3)
</code></pre>
<p>I’m trying to use it for 3D CT/MRI data. so, upsampling or downsampling methods on the depth axis should be reasonable.</p>

username: Matias_Vasquez
cooked: <p>You can use <code>torch.nn.Upsample</code>.</p>
<p>But your data has to be in one of the following formats<br>
<img src="https://discuss.pytorch.org/uploads/default/original/3X/0/b/0bee144a5501fa80bbfee076e4f07f88e6f36c70.png" alt="image" data-base62-sha1="1HxkKkYbp217cmDJKmjn6Fl9vJC" width="629" height="237"></p>
<p><a href="https://pytorch.org/docs/stable/generated/torch.nn.Upsample.html" rel="noopener nofollow ugc">Here</a> is the documentation. Here you can see HOW you want to do the interpolation, since it will change if you use <code>nearest</code>, <code>bilinear</code> or something else.</p>
<p>Hope this helps <img src="https://discuss.pytorch.org/images/emoji/apple/smile.png?v=12" title=":smile:" class="emoji" alt=":smile:" loading="lazy" width="20" height="20"></p>

username: Innat
cooked: <p>Thanks. Seeing the layer name, is it also possible to downsample the input with this upsample layer?</p>

username: Matias_Vasquez
cooked: <p>Yes, you can also specify the size that you want instead of a scaling factor</p>
<pre><code class="lang-python"># Example
a = torch.rand(3, 3, 40, 256, 256)
up = torch.nn.Upsample(size=(80, 512, 512))
down = torch.nn.Upsample(size=(20, 128, 128))

print('down = ', down(a).shape)
print('up = ', up(a).shape)

# Output
# up =  torch.Size([3, 3, 80, 512, 512])
# down =  torch.Size([3, 3, 20, 128, 128])
</code></pre>

username: Innat
cooked: <p>Thanks, <a class="mention" href="/u/matias_vasquez">@Matias_Vasquez</a>. I think the layer name should be <code>torch.nn.Resample</code>.</p>
<p>I like to know how <code>torch.nn.Upsample</code> works for downsampling. In the <code>depth</code> part of volumetric data, it might be hard to decide the appropriate strategy to drop the slices depending on the domain.</p>
<p>For example, in medical data, if we drop the slice blindly, we might lose information. I mean, in CT/MRI images, most of the slice information appears mainly in the <strong>middle range</strong> of depth.</p>
<pre><code class="lang-auto">a = torch.rand(3, 3, 40, 256, 256)

down = torch.nn.Upsample(size=(20, 128, 128))
torch.Size([3, 3, 20, 128, 128])
</code></pre>
<p>So, how does <code>40</code> becomes <code>20</code>. Which slices are dropped?</p>
<pre><code class="lang-auto">D(out) = D(in) * scale_factor ... ?
</code></pre>

username: Matias_Vasquez
cooked: <p>This is what you need to decide when you give the <code>mode</code> parameter. The default value (if you do not specify) is <code>nearest</code>.</p>
<p>For the case where you divide the size by 2, means that every even (or uneven) row/column will be dropped and the value will be taken from the <code>nearest</code> values. Which would be the actual value of the row/column that is not deleted. If you choose something like <code>bilinear</code> then a line will be computed from <code>voxel</code> to <code>voxel</code> and the value in between will be chosen.</p>
<p>However, if you say that the most important information is in the middle, then you can slice your data first. This way you will select the parts that matter the most to you and retaining more valuable information.</p>
<p>After slicing you can then still downsample, but less data will be lost in order to get the same size.</p>
<p>Since the scaling factor will be smaller (not dividing by 2 but 1.5 for example) then the values will be computed depending on the mode selected.</p>

username: mikbuch
cooked: <p>I had a similar issue with spatially normalising (i.e., resampling) 3D volumetric CT images. It was easiest to do with <code>scipy</code>’s <code>zoom</code> function:</p>
<p>I had scans of the size of 512 x 512 x Y (where Y was varying number of slices), and the intended number of slices was 352. Hence, I did:</p>
<pre><code class="lang-auto">from scipy.ndimage import zoom

scan = zoom(scan, (1, 1, 352/scan.shape[-1]))
</code></pre>
<p>Only after that operation I used the data in PyTorch.</p>