Skip to content

Commit 4ade3bc

Browse files
committed
various changes to 360 centering and morphing 360 to 180 methods
1 parent b582acc commit 4ade3bc

File tree

6 files changed

+46
-43
lines changed

6 files changed

+46
-43
lines changed

httomolibgpu/misc/morph.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545

4646
def sino_360_to_180(
47-
data: cp.ndarray, overlap: int = 0, rotation: Literal["left", "right"] = "left"
47+
data: cp.ndarray, overlap: float = 0, side: Literal["left", "right"] = "left"
4848
) -> cp.ndarray:
4949
"""
5050
Converts 0-360 degrees sinogram to a 0-180 sinogram.
@@ -55,9 +55,9 @@ def sino_360_to_180(
5555
----------
5656
data : cp.ndarray
5757
Input 3D data.
58-
overlap : scalar, optional
59-
Overlapping number of pixels.
60-
rotation : string, optional
58+
overlap : float
59+
Overlapping number of pixels. Floats will be converted to integers.
60+
side : string
6161
'left' if rotation center is close to the left of the
6262
field-of-view, 'right' otherwise.
6363
Returns
@@ -74,26 +74,28 @@ def sino_360_to_180(
7474

7575
overlap = int(np.round(overlap))
7676
if overlap >= dz:
77-
raise ValueError("overlap must be less than data.shape[2]")
77+
raise ValueError("Overlap must be less than data.shape[2]")
7878
if overlap < 0:
79-
raise ValueError("only positive overlaps are allowed.")
79+
raise ValueError("Only positive overlaps are allowed.")
8080

81-
if rotation not in ["left", "right"]:
82-
raise ValueError('rotation parameter must be either "left" or "right"')
81+
if side not in ["left", "right"]:
82+
raise ValueError(
83+
f'The value {side} is invalid, only "left" or "right" strings are accepted'
84+
)
8385

8486
n = dx // 2
8587

8688
out = cp.empty((n, dy, 2 * dz - overlap), dtype=data.dtype)
8789

88-
if rotation == "left":
90+
if side == "left":
8991
weights = cp.linspace(0, 1.0, overlap, dtype=cp.float32)
9092
out[:, :, -dz + overlap :] = data[:n, :, overlap:]
9193
out[:, :, : dz - overlap] = data[n : 2 * n, :, overlap:][:, :, ::-1]
9294
out[:, :, dz - overlap : dz] = (
9395
weights * data[:n, :, :overlap]
9496
+ (weights * data[n : 2 * n, :, :overlap])[:, :, ::-1]
9597
)
96-
if rotation == "right":
98+
if side == "right":
9799
weights = cp.linspace(1.0, 0, overlap, dtype=cp.float32)
98100
out[:, :, : dz - overlap] = data[:n, :, :-overlap]
99101
out[:, :, -dz + overlap :] = data[n : 2 * n, :, :-overlap][:, :, ::-1]

httomolibgpu/recon/rotation.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -416,27 +416,26 @@ def find_center_360(
416416
data: cp.ndarray,
417417
ind: Optional[int] = None,
418418
win_width: int = 10,
419-
side: Optional[Literal[0, 1]] = None,
419+
side: Optional[Literal["left", "right"]] = None,
420420
denoise: bool = True,
421421
norm: bool = False,
422422
use_overlap: bool = False,
423-
) -> Tuple[float, float, Optional[Literal[0, 1]], float]:
423+
) -> Tuple[np.float32, np.float32, Optional[Literal["left", "right"]], np.float32]:
424424
"""
425425
Find the center-of-rotation (COR) in a 360-degree scan and also an offset
426426
to perform data transformation from 360 to 180 degrees scan. See :cite:`vo2021data`.
427427
428-
Parameters
428+
Parameters Tuple[np.float32, np.float32, Literal["left", "right"], np.float32]:
429429
----------
430430
data : cp.ndarray
431431
3D tomographic data as a Cupy array.
432432
ind : int, optional
433433
Index of the slice to be used for estimate the CoR and the overlap.
434434
win_width : int, optional
435435
Window width used for finding the overlap area.
436-
side : {None, 0, 1}, optional
437-
Overlap size. Only there options: None, 0, or 1. "None" corresponds
438-
to fully automated determination. "0" corresponds to the left side.
439-
"1" corresponds to the right side.
436+
side : {None, left, right}, optional
437+
Chose between "left", "right" or "None" which corresponds to fully
438+
automated determination of the side.
440439
denoise : bool, optional
441440
Apply the Gaussian filter if True.
442441
norm : bool, optional
@@ -451,8 +450,8 @@ def find_center_360(
451450
Center-of-rotation.
452451
overlap : float
453452
Width of the overlap area between two halves of the sinogram.
454-
side : int
455-
Overlap side between two halves of the sinogram.
453+
side : str
454+
Overlap side (left or right) between two halves of the sinogram.
456455
overlap_position : float
457456
Position of the window in the first image giving the best
458457
correlation metric.
@@ -475,8 +474,9 @@ def find_center_360(
475474
(overlap, side, overlap_position) = _find_overlap(
476475
sino_top, sino_bot, win_width, side, denoise, norm, use_overlap
477476
)
478-
if side == 0:
479-
cor = overlap / 2.0 - 1.0
477+
if side == "left":
478+
# cor = overlap / 2.0 - 1.0
479+
cor = ncol // 2 # NOTE: major correction to check!
480480
else:
481481
cor = ncol - overlap / 2.0 - 1.0
482482

@@ -498,10 +498,9 @@ def _find_overlap(
498498
2D array. Projection image or sinogram image.
499499
win_width : int
500500
Width of the searching window.
501-
side : {None, 0, 1}, optional
502-
Only there options: None, 0, or 1. "None" corresponding to fully
503-
automated determination. "0" corresponding to the left side. "1"
504-
corresponding to the right side.
501+
side : {None, left, right}, optional
502+
Chose between "left", "right" or "None" which corresponds to fully
503+
automated determination of the side.
505504
denoise : bool, optional
506505
Apply the Gaussian filter if True.
507506
norm : bool, optional
@@ -514,8 +513,8 @@ def _find_overlap(
514513
-------
515514
overlap : float
516515
Width of the overlap area between two images.
517-
side : int
518-
Overlap side between two images.
516+
side : str
517+
Overlap side (left or right) between two images.
519518
overlap_position : float
520519
Position of the window in the first image giving the best
521520
correlation metric.
@@ -525,25 +524,25 @@ def _find_overlap(
525524
ncol2 = mat2.shape[1]
526525
win_width = int(np.clip(win_width, 6, min(ncol1, ncol2) // 2))
527526

528-
if side == 1:
527+
if side == "right":
529528
(list_metric, offset) = _search_overlap(
530529
mat1,
531530
mat2,
532531
win_width,
533-
side=side,
532+
side=1, # right side
534533
denoise=denoise,
535534
norm=norm,
536535
use_overlap=use_overlap,
537536
)
538537
overlap_position = _calculate_curvature(list_metric)[1]
539538
overlap_position += offset
540539
overlap = ncol1 - overlap_position + win_width // 2
541-
elif side == 0:
540+
elif side == "left":
542541
(list_metric, offset) = _search_overlap(
543542
mat1,
544543
mat2,
545544
win_width,
546-
side=side,
545+
side=0, # left side
547546
denoise=denoise,
548547
norm=norm,
549548
use_overlap=use_overlap,
@@ -556,7 +555,7 @@ def _find_overlap(
556555
mat1,
557556
mat2,
558557
win_width,
559-
side=1,
558+
side=1, # right side
560559
denoise=denoise,
561560
norm=norm,
562561
use_overlap=use_overlap,
@@ -565,7 +564,7 @@ def _find_overlap(
565564
mat1,
566565
mat2,
567566
win_width,
568-
side=0,
567+
side=0, # left side
569568
denoise=denoise,
570569
norm=norm,
571570
use_overlap=use_overlap,
@@ -577,11 +576,11 @@ def _find_overlap(
577576
overlap_position2 += offset2
578577

579578
if curvature1 > curvature2:
580-
side = 1
579+
side = "right"
581580
overlap_position = overlap_position1
582581
overlap = ncol1 - overlap_position + win_width // 2
583582
else:
584-
side = 0
583+
side = "left"
585584
overlap_position = overlap_position2
586585
overlap = overlap_position + win_width // 2
587586

tests/test_recon/test_rotation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def test_find_center_360_NaN_infs_raises(data, flats, darks):
126126
@pytest.mark.parametrize("norm", [False, True], ids=["no_normalise", "normalise"])
127127
@pytest.mark.parametrize("overlap", [False, True], ids=["no_overlap", "overlap"])
128128
@pytest.mark.parametrize("denoise", [False, True], ids=["no_denoise", "denoise"])
129-
@pytest.mark.parametrize("side", [1, 0])
129+
@pytest.mark.parametrize("side", ["right", "left"])
130130
@cp.testing.numpy_cupy_allclose(rtol=1e-5, atol=1e-6)
131131
def test_find_center_360_unity(ensure_clean_memory, xp, norm, overlap, denoise, side):
132132
# because it's random, we explicitly seed and use numpy only, to match the data

zenodo-tests/test_misc/test_morph.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def test_sino_360_to_180_i13_dataset1(i13_dataset1):
2020
force_clean_gpu_memory()
2121

2222
stiched_data_180degrees = sino_360_to_180(
23-
data_normalised, overlap=473.822265625, rotation="right"
23+
data_normalised, overlap=473.822265625, side="right"
2424
)
2525
stiched_data_180degrees = stiched_data_180degrees.get()
2626

@@ -41,7 +41,7 @@ def test_sino_360_to_180_i13_dataset3(i13_dataset3):
4141
force_clean_gpu_memory()
4242

4343
stiched_data_180degrees = sino_360_to_180(
44-
data_normalised, overlap=438.173828, rotation="left"
44+
data_normalised, overlap=438.173828, side="left"
4545
)
4646
stiched_data_180degrees = stiched_data_180degrees.get()
4747

zenodo-tests/test_recon/test_algorithm.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import cupy as cp
32
import numpy as np
43
import pytest
@@ -114,7 +113,7 @@ def test_reconstruct_LPRec_tomobar_i13_dataset1(i13_dataset1):
114113
force_clean_gpu_memory()
115114

116115
stiched_data_180degrees = sino_360_to_180(
117-
data_normalised[:, 2:3, :], overlap=473.822265625, rotation="right"
116+
data_normalised[:, 2:3, :], overlap=473.822265625, side="right"
118117
)
119118
del data_normalised
120119
force_clean_gpu_memory()
@@ -208,7 +207,7 @@ def test_reconstruct_LPRec3d_tomobar_i13_dataset2(i13_dataset2):
208207

209208
assert isclose(np.sum(recon_data), 4095.6257, abs_tol=10**-3)
210209
assert pytest.approx(np.max(recon_data), rel=1e-3) == 0.0105672
211-
assert pytest.approx(np.min(recon_data), rel=1e-3) == -0.00839
210+
assert pytest.approx(np.min(recon_data), rel=1e-3) == -0.00839
212211
assert recon_data.dtype == np.float32
213212
assert recon_data.shape == (2560, 10, 2560)
214213

@@ -262,7 +261,7 @@ def test_reconstruct_FBP3d_tomobar_i13_dataset3(i13_dataset3):
262261
force_clean_gpu_memory()
263262

264263
stiched_data_180degrees = sino_360_to_180(
265-
data_normalised, overlap=438.173828, rotation="left"
264+
data_normalised, overlap=438.173828, side="left"
266265
)
267266
force_clean_gpu_memory()
268267

@@ -278,5 +277,6 @@ def test_reconstruct_FBP3d_tomobar_i13_dataset3(i13_dataset3):
278277

279278
assert recon_data.flags.c_contiguous
280279
recon_data = recon_data.get()
280+
281281
assert recon_data.dtype == np.float32
282282
assert recon_data.shape == (4682, 3, 4682)

zenodo-tests/test_recon/test_rotation.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ def test_center_360_i13_dataset1(i13_dataset1, ensure_clean_memory):
140140
cor, overlap, side, overlap_position = find_center_360(data_normalised)
141141

142142
assert int(cor) == 2322
143+
assert side == "right"
143144
assert int(overlap) == 473 # actual 473.822265625
144145
assert cor.dtype == np.float64
145146

@@ -183,13 +184,14 @@ def test_center_360_i13_dataset3(i13_dataset3, ensure_clean_memory):
183184
data_normalised,
184185
ind=1,
185186
win_width=50,
186-
side=0,
187+
side="left",
187188
denoise=True,
188189
norm=True,
189190
use_overlap=True,
190191
)
191192

192193
assert int(cor) == 218 # actual 218.08 (not correct CoR actually, should be 2341)
194+
assert side == "left"
193195
assert int(overlap) == 438 # actual 438.173828
194196
assert cor.dtype == np.float64
195197

0 commit comments

Comments
 (0)