Commit 4a159813 authored by Pierre Paleo's avatar Pierre Paleo

Merge branch 'half_tomo_cor_preproc' into 'master'

Half tomo: auto-CoR

See merge request !59
parents d5eb5513 e21b70cc
Pipeline #35076 passed with stages
in 13 minutes and 27 seconds
This diff is collapsed.
This diff is collapsed.
import numpy as np
from silx.io import get_data
from ..preproc.ccd import FlatField
from ..preproc.alignment import CenterOfRotation
from ..preproc.alignment import CenterOfRotation, CenterOfRotationAdaptiveSearch
class CORFinder:
"""
......@@ -29,23 +29,35 @@ class CORFinder:
self._init_flatfield()
self._apply_flatfield()
self.cor = CenterOfRotation()
self._default_search_method = "centered"
if self.halftomo:
self._default_search_method = "global"
self.cor = CenterOfRotationAdaptiveSearch()
def _get_angles(self, angles):
dataset_angles = self.dataset_info.rotation_angles
if dataset_angles is None:
if angles is None: # should not happen with hdf5
print("Warning: no information on angles was found for this dataset. Using default [0, 180[ range.")
angles = np.linspace(0, np.pi, len(self.dataset_info.projections), False)
theta_min = 0
theta_max = np.pi
msg = "Warning: no information on angles was found for this dataset. Using default range "
endpoint = False
if self.halftomo:
theta_max *= 2
endpoint = True
msg += "[0, 360]"
else:
msg += "[0, 180["
print(msg)
angles = np.linspace(
theta_min, theta_max, len(self.dataset_info.projections),
endpoint=endpoint
)
dataset_angles = angles
self.angles = dataset_angles
def _init_radios(self):
# TODO
if self.halftomo:
raise NotImplementedError("Automatic COR with half tomo is not supported yet")
#
# We take 2 radios. It could be tuned for a 360 degrees scan.
self._n_radios = 2
self._radios_indices = []
......@@ -80,24 +92,37 @@ class CORFinder:
self.flatfield.normalize_radios(self.radios)
def find_cor(self, **cor_kwargs):
def find_cor(self, search_method=None, **cor_kwargs):
"""
Find the center of rotation.
Parameters
----------
This function passes the named parameters to nabu.preproc.alignment.CenterOfRotation.find_shift.
search_method: str, optional
Which CoR search method to use. Default is "auto" (equivalent to "centered").
Returns
-------
cor: float
The estimated center of rotation for the current dataset.
Notes
------
This function passes the named parameters to nabu.preproc.alignment.CenterOfRotation.find_shift.
"""
shift = self.cor.find_shift(
self.radios[0],
np.fliplr(self.radios[1]),
**cor_kwargs
)
search_method = search_method or self._default_search_method
if search_method == "global":
shift = self.cor.find_shift(
self.radios[0],
np.fliplr(self.radios[1]),
low_pass=1, high_pass=20
)
else:
shift = self.cor.find_shift(
self.radios[0],
np.fliplr(self.radios[1]),
**cor_kwargs
)
# find_shift returned a single scalar in 2020.1
# This should be the default after 2020.2 release
if hasattr(shift, "__iter__"):
......
......@@ -58,7 +58,7 @@ class NabuValidator(object):
ny = nx
if self.nabu_config["reconstruction"]["enable_halftomo"]:
if self.dataset_infos.axis_position is None:
raise ValueError("rotation_axis_position should be either a number or 'auto' for half tomo")
raise ValueError("Cannot use rotation axis position in the middle of the detector when half tomo is enabled")
cor = int(round(self.dataset_infos.axis_position))
ny = nx = 2*cor
what = (
......@@ -199,7 +199,7 @@ class NabuValidator(object):
nx, nz = self.dataset_infos.radio_dims
rec_params = self.nabu_config["reconstruction"]
if rec_params["enable_halftomo"]:
cor = int(round(rec_params["rotation_axis_position"]))
cor = int(round(self.dataset_infos.axis_position))
ny = nx = 2*cor
what = (
("start_x", "end_x", nx),
......
......@@ -134,3 +134,17 @@ sino_normalizations = {
"": None,
"chebyshev": "chebyshev",
}
class CorMethods(Enum):
AUTO = "centered"
CENTERED = "centered"
GLOBAL = "global"
cor_methods = {
"auto": "centered",
"centered": "centered",
"global": "global",
}
......@@ -78,12 +78,12 @@ class ProcessConfig:
def _get_cor(self):
cor = self.nabu_config["reconstruction"]["rotation_axis_position"]
if cor == "auto":
if isinstance(cor, str): # auto-CoR
self.corfinder = CORFinder(
self.dataset_infos,
halftomo=self.nabu_config["reconstruction"]["enable_halftomo"],
)
cor = self.corfinder.find_cor()
cor = self.corfinder.find_cor(search_method=cor)
self.dataset_infos.axis_position = cor
......@@ -223,7 +223,7 @@ class ProcessConfig:
# New key
rec_options["rotation_axis_position_halftomo"] = (2*cor_i-1)/2.
# New key
rec_options["cor_estimated_auto"] = (nabu_config["reconstruction"]["rotation_axis_position"] == "auto")
rec_options["cor_estimated_auto"] = isinstance(nabu_config["reconstruction"]["rotation_axis_position"], str)
#
# Histogram
......
......@@ -217,16 +217,18 @@ def optional_float_validator(val):
@validator
def cor_validator(val):
if isinstance(val, float):
return val
elif len(val.strip()) >= 1:
if val.lower() == "auto":
return "auto"
val_float, error = convert_to_float(val)
assert error is None, "Invalid number"
val_float, error = convert_to_float(val)
if error is None:
return val_float
else:
if len(val.strip()) == 0:
return None
val = name_range_checker(
val.lower(),
CorMethods.values(),
"center of rotation estimation method",
replacements=cor_methods
)
return val
@validator
......
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