Skip to content

Commit ebb7f5a

Browse files
author
Marc Karimi
committed
Pr and naming changes
1 parent 4e9b928 commit ebb7f5a

File tree

2 files changed

+36
-30
lines changed

2 files changed

+36
-30
lines changed

src/aspire/line/line.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,24 @@
1212
class Line:
1313
def __init__(self, data, dtype=np.float64):
1414
"""
15-
Initialize a Line Object. Change later (similar intuition from Image class)
15+
Initialize a Line Object. This is a stack of one or more line projections or sinograms.
16+
17+
The stack can be multidimensional with 'n' equal to the product
18+
of the stack dimensions. Singletons will be expanded into a stack
19+
with one entry.
1620
1721
:param data: Numpy array containing image data with shape
18-
`(..., resolution, resolution)`.
22+
`(..., angles, radial points)`.
1923
:param dtype: Optionally cast `data` to this dtype.
2024
Defaults to `data.dtype`.
2125
"""
2226
self.dtype = np.dtype(dtype)
2327
if data.ndim == 2:
2428
data = data[np.newaxis, :, :]
2529
if data.ndim < 3:
26-
assert "Projection Dimensions should be more than Three-Dimensions"
30+
raise ValueError(
31+
f"Invalid data shape: {data.shape}. Expected shape: (..., angles, radial_points), where '...' is the stack number."
32+
)
2733
self._data = data.astype(self.dtype, copy=False)
2834
self.ndim = self._data.ndim
2935
self.shape = self._data.shape
@@ -71,7 +77,7 @@ def stack_reshape(self, *args):
7177
# Sanity check the size
7278
if shape != (-1,) and np.prod(shape) != self.n:
7379
raise ValueError(
74-
f"Number of sinogram images {self.n_images} cannot be reshaped to {shape}."
80+
f"Number of sinogram images {self.n} cannot be reshaped to {shape}."
7581
)
7682

7783
return self.__class__(self._data.reshape(*shape, *self._data.shape[-2:]))
@@ -94,23 +100,17 @@ def copy(self):
94100
def __str__(self):
95101
return f"Line(n_images = {self.n}, n_angles = {self.n_points}, n_radial_points = {self.n_radial_points})"
96102

97-
@property
98-
def stack(self):
99-
return self.n_images
100-
101-
def back_project(self, angles):
103+
def backproject(self, angles):
102104
"""
103105
Back Projection Method for a single stack of lines.
104106
105-
:param filter_name: string, optional
106-
Filter used in frequency domain filtering. Assign None to use no filter.
107-
:param angles: array
108-
assuming not perfectly radial angles
109-
:return: stack of reconstructed
107+
:param angles: np.ndarray
108+
1D array of angles in radians. Each entry in the array corresponds to a different number of angles which are used to reconstruct the image.
109+
:return: Aspire Image
110+
An Image object containing the original stack size with a newly reconstructed numpy array of the images. Expected return shape should be (n_images, n_angles, n_radial_points)
110111
"""
111-
assert (
112-
len(angles) == self.n_angles
113-
), "Number of angles must match the number of projections"
112+
if len(angles) != self.n_angles:
113+
raise ValueError("Number of angles must match the number of projections.")
114114

115115
original_stack_shape = self.stack_shape
116116
sinogram = xp.asarray(self.stack_reshape(-1)._data)

tests/test_sinogram.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,18 @@ def test_project_multidim(num_ang):
144144
)
145145

146146

147-
def test_back_project_single(masked_image, num_ang):
147+
def test_backproject_single(masked_image, num_ang):
148148
"""
149-
Test Line.backproject on a single stack of line projections or sinogram. Compares the reconstructed image to original.
149+
Test Line.backproject on a single stack of line projections (sinograms).
150+
151+
This test compares the reconstructed image from the `backproject` method to
152+
the skimage method `iradon.`
150153
"""
151154
angles = np.linspace(0, 360, num_ang, endpoint=False)
152155
rads = angles / 180 * np.pi
153156
sinogram = masked_image.project(rads)
154157
sinogram_np = sinogram.asnumpy()
155-
back_project = sinogram.back_project(rads)
158+
back_project = sinogram.backproject(rads)
156159

157160
assert masked_image.shape == back_project.shape, "The shape must be the same."
158161

@@ -168,16 +171,18 @@ def test_back_project_single(masked_image, num_ang):
168171
# we apply a normalized root mean square error on the images to find relative error to range of ref. image
169172
# Note: tolerance is typically < 0.2 regardless of angles, pixels, etc.
170173
nrmse = np.sqrt(np.mean((our_back_project - sk_image_iradon) ** 2)) / (
171-
np.max(sk_image_iradon - np.min(sk_image_iradon))
174+
np.max(sk_image_iradon) - np.min(sk_image_iradon)
172175
)
173176
assert (
174177
nrmse < SK_TOL_BACKPROJECT
175178
), f"NRMSE is too high: {nrmse}, expected less than {SK_TOL_BACKPROJECT}"
176179

177180

178-
def test_back_project_multidim(num_ang):
181+
def test_backproject_multidim(num_ang):
179182
"""
180-
Test Line.backproject on a stack of images. Extension of back_project_single but for multi-dimensional stacks. Similar to forward_multidim test.
183+
Test Line.backproject on a stack of line projections.
184+
185+
Extension of the `backproject_single` test but checks for multi-dimensional stacks.
181186
"""
182187
L = 512 # pixels
183188
n = 3
@@ -193,7 +198,7 @@ def test_back_project_multidim(num_ang):
193198

194199
# apply a forward project on the image, then backwards
195200
ours_forward = imgs.project(rads)
196-
ours_backward = ours_forward.back_project(rads)
201+
ours_backward = ours_forward.backproject(rads)
197202

198203
# Compare
199204
reference_back_projects = np.empty((m, n, L, L))
@@ -202,7 +207,7 @@ def test_back_project_multidim(num_ang):
202207
img = imgs[i, j]
203208
# Compute the singleton case, and compare with stack.
204209
single_sinogram = img.project(rads)
205-
back_project = single_sinogram.back_project(rads)
210+
back_project = single_sinogram.backproject(rads)
206211

207212
# These should be allclose up to determinism.
208213
np.testing.assert_allclose(ours_backward[i, j : j + 1], back_project[0])
@@ -212,11 +217,12 @@ def test_back_project_multidim(num_ang):
212217
single_sinogram.asnumpy()[0].T, theta=angles[::-1], filter_name=None
213218
)
214219

215-
# apply a mask, then find the NRMSE on the collection of images
216-
# similar tolerance level to single project test
220+
# apply a mask, then find the NRMSE on the collection of images
221+
# similar tolerance level to single project test
217222
nrmse = np.sqrt(
218223
np.mean((ours_backward.asnumpy() * mask - reference_back_projects) ** 2)
219224
) / (np.max(reference_back_projects) - np.min(reference_back_projects))
220-
assert (
221-
nrmse < SK_TOL_BACKPROJECT
222-
), f"NRMSE is too high for image ({i},{j}): {nrmse}, expected less than {SK_TOL_BACKPROJECT}"
225+
226+
np.testing.assert_array_less(
227+
nrmse, SK_TOL_BACKPROJECT, "Error with the reconstructed images."
228+
)

0 commit comments

Comments
 (0)