Commit f1b656d9 authored by Pierre Paleo's avatar Pierre Paleo

Compute end_xy with binning

parent 3b68f7d0
......@@ -459,10 +459,10 @@ class FullFieldPipeline:
@use_options("reconstruction", "reconstruction")
def _prepare_reconstruction(self):
options = self.processing_options["reconstruction"]
x_s, x_e = options["start_x"], options["end_x"]+1
y_s, y_e = options["start_y"], options["end_y"]+1
self._rec_roi = (x_s, x_e, y_s, y_e)
self._allocate_recs(y_e - y_s, x_e - x_s)
x_s, x_e = options["start_x"], options["end_x"]
y_s, y_e = options["start_y"], options["end_y"]
self._rec_roi = (x_s, x_e + 1, y_s, y_e + 1)
self._allocate_recs(y_e - y_s + 1, x_e - x_s + 1)
@use_options("reconstruction", "reconstruction")
......
......@@ -50,12 +50,13 @@ class NabuValidator(object):
return res
def _get_nx_ny(self):
def _get_nx_ny(self, binning=1):
if self.nabu_config["reconstruction"]["enable_halftomo"]:
cor = int(round(self.dataset_infos.axis_position))
nx = max(2*cor, 2 * (self.dataset_infos.radio_dims[0] - 1 - cor))
cor = int(round(self.dataset_infos.axis_position / binning))
nx = self.dataset_infos.radio_dims[0] // binning
nx = max(2*cor, 2 * (nx - 1 - cor))
else:
nx, nz = self.dataset_infos.radio_dims
nx = self.dataset_infos.radio_dims[0] // binning
ny = nx
return nx, ny
......@@ -270,22 +271,22 @@ class NabuValidator(object):
self.dataset_infos.n_angles //= subsampling_factor
if self.binning != (1, 1):
bin_x, bin_z = self.binning
bin_y = bin_x # square slices
# Update end_x, end_y, end_z
rec_cfg = self.nabu_config["reconstruction"]
end_x, end_y = self.get_end_xy() # Not so trivial. See function documentation
rec_cfg["end_x"] = end_x
rec_cfg["end_y"] = end_y
rec_cfg["end_z"] = (rec_cfg["end_z"] + 1) // bin_z - 1
rec_cfg["start_x"] = (rec_cfg["start_x"] // bin_x)
rec_cfg["start_y"] = (rec_cfg["start_y"] // bin_y)
rec_cfg["start_z"] = (rec_cfg["start_z"] // bin_z)
# Update radio_dims
nx, nz = self.dataset_infos.radio_dims
nx //= bin_x
ny = nx # square slices
nz //= bin_z
self.dataset_infos.radio_dims = (nx, nz)
rec_cfg = self.nabu_config["reconstruction"]
end_x = rec_cfg["end_x"]
end_y = rec_cfg["end_y"]
end_z = rec_cfg["end_z"]
bin_y = bin_x # square slices
rec_cfg["end_x"] = (end_x // bin_x) - ((nx % bin_x) != 0)
rec_cfg["end_y"] = (end_y // bin_y) - ((ny % bin_y) != 0)
rec_cfg["end_z"] = (end_z // bin_z) - ((nz % bin_z) != 0)
rec_cfg["start_x"] = (rec_cfg["start_x"] // bin_x)
rec_cfg["start_y"] = (rec_cfg["start_y"] // bin_y)
rec_cfg["start_z"] = (rec_cfg["start_z"] // bin_z)
# Update the Rotation center
# TODO axis_corrections
rot_c = self.dataset_infos.axis_position
......@@ -316,3 +317,74 @@ class NabuValidator(object):
# TODO handle other modes
def get_end_xy(self):
"""
Return the "end_x" value for reconstruction, accounting for binning.
There are three situations:
1. Normal setting: Nx_rec = Nx
2. Half acquisition, CoR on the right side: Nx_rec = 2 * |c|
3. Half acquisition, CoR on the left side: Nx_rec = 2 * (Nx - 1 - |c|)
where |c| = int(round(c)).
**Without binnig**
Let e0 denote the default value for "end_x", without user modification.
By default, all the slice is reconstructed, so
e0 = Nx_rec - 1
Let e denote the user value for "end_x". By default e = e0, but the user might
want to tune it.
Let d denote the distance between e and e0: d = e0 - e. By default d = 0.
**With binning**
Let b denote the binning value in x.
1. Nx' = Nx // b
2. Nx' = 2 * |c/b|
3. Nx' = 2 * (Nx//b - 1 - |c/b|)
With the same notations, with a prime suffix, we have:
* e0' = Nx' - 1 is the default value of "end_x" accounting for binning
* e' is the user value for "end_x" accounting for binning
* d' = e0' - e' is the distance between e0' and e'
In the standard setting (no half tomography), computing e' (i.e end_x) is straightforward:
e' = (e+1)//b - 1
With half tomography, because of the presence of |c| = int(floor(c)), the things
are a bit more difficult.
We enforce the following invariant in all settings:
(I1) dist(e0', e') = dist(e0, e) // b
Another possible invariant is
(I2) delta_x' = delta_x // b
Which is equivalent to (I1) only in setting (1) (i.e no half-tomography).
In the half-tomography setting, (I1) and (I2) are not equivalent anymore, so we have
to choose between the two.
We believe it is more consistent to preserve "end_x", so that a user not modying "end_x"
ends up with all the range [0, Nx - 1] reconstructed.
Therefore:
e' = e0' - d//b
"""
b, _ = self.binning
end_xy = []
for i in range(2):
what = ["end_x", "end_y"][i]
e0 = self._get_nx_ny()[i] - 1
e0p = self._get_nx_ny(binning=b)[i] - 1
d = e0 - self.nabu_config["reconstruction"][what]
ep = e0p - d//b
end_xy.append(ep)
return tuple(end_xy)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment