1
|
|
|
import numpy as np |
2
|
|
|
from nibabel.affines import apply_affine |
3
|
|
|
|
4
|
|
|
from ....data.subject import Subject |
5
|
|
|
from .bounds_transform import BoundsTransform |
6
|
|
|
from .bounds_transform import TypeBounds |
7
|
|
|
|
8
|
|
|
|
9
|
|
|
class Crop(BoundsTransform): |
10
|
|
|
r"""Crop an image. |
11
|
|
|
|
12
|
|
|
Args: |
13
|
|
|
cropping: Tuple |
14
|
|
|
:math:`(w_{ini}, w_{fin}, h_{ini}, h_{fin}, d_{ini}, d_{fin})` |
15
|
|
|
defining the number of values cropped from the edges of each axis. |
16
|
|
|
If the initial shape of the image is |
17
|
|
|
:math:`W \times H \times D`, the final shape will be |
18
|
|
|
:math:`(- w_{ini} + W - w_{fin}) \times (- h_{ini} + H - h_{fin}) |
19
|
|
|
\times (- d_{ini} + D - d_{fin})`. |
20
|
|
|
If only three values :math:`(w, h, d)` are provided, then |
21
|
|
|
:math:`w_{ini} = w_{fin} = w`, |
22
|
|
|
:math:`h_{ini} = h_{fin} = h` and |
23
|
|
|
:math:`d_{ini} = d_{fin} = d`. |
24
|
|
|
If only one value :math:`n` is provided, then |
25
|
|
|
:math:`w_{ini} = w_{fin} = h_{ini} = h_{fin} |
26
|
|
|
= d_{ini} = d_{fin} = n`. |
27
|
|
|
**kwargs: See :class:`~torchio.transforms.Transform` for additional |
28
|
|
|
keyword arguments. |
29
|
|
|
|
30
|
|
|
.. seealso:: If you want to pass the output shape instead, please use |
31
|
|
|
:class:`~torchio.transforms.CropOrPad` instead. |
32
|
|
|
""" |
33
|
|
|
|
34
|
|
|
def __init__(self, cropping: TypeBounds, **kwargs): |
35
|
|
|
super().__init__(cropping, **kwargs) |
36
|
|
|
self.cropping = cropping |
37
|
|
|
self.args_names = ['cropping'] |
38
|
|
|
|
39
|
|
|
def apply_transform(self, subject: Subject) -> Subject: |
40
|
|
|
assert self.bounds_parameters is not None |
41
|
|
|
low = self.bounds_parameters[::2] |
42
|
|
|
high = self.bounds_parameters[1::2] |
43
|
|
|
index_ini = low |
44
|
|
|
index_fin = np.array(subject.spatial_shape) - high |
45
|
|
|
for image in self.get_images(subject): |
46
|
|
|
new_origin = apply_affine(image.affine, index_ini) |
47
|
|
|
new_affine = image.affine.copy() |
48
|
|
|
new_affine[:3, 3] = new_origin |
49
|
|
|
i0, j0, k0 = index_ini |
50
|
|
|
i1, j1, k1 = index_fin |
51
|
|
|
image.set_data(image.data[:, i0:i1, j0:j1, k0:k1].clone()) |
52
|
|
|
image.affine = new_affine |
53
|
|
|
return subject |
54
|
|
|
|
55
|
|
|
def inverse(self): |
56
|
|
|
from .pad import Pad |
57
|
|
|
|
58
|
|
|
return Pad(self.cropping) |
59
|
|
|
|