Source code for nabu.app.multicor
from os import remove
import numpy as np
from .. import version
from .reconstruct import get_reconstructor
from .cli_configs import MultiCorConfig
from .utils import parse_params_values
from ..utils import view_as_images_stack
[docs]
def get_user_cors(cors):
"""
From a user-provided str describing the centers of rotation, build a list.
"""
cors = cors.strip("[()]")
cors = cors.split(",")
cors = [c.strip() for c in cors]
cors_list = []
for c in cors:
if ":" in c:
if c.count(":") != 2:
raise ValueError("Malformed range format for '%s': expected format start:stop:step" % c)
start, stop, step = c.split(":")
c_list = np.arange(float(start), float(stop), float(step)).tolist()
else:
c_list = [float(c)]
cors_list.extend(c_list)
return cors_list
[docs]
def main():
args = parse_params_values(
MultiCorConfig,
parser_description=f"Perform a tomographic reconstruction of a single slice using multiple centers of rotation",
program_version="nabu " + version,
)
reconstructor = get_reconstructor(
args,
# Put a dummy CoR to avoid crash in both full-FoV and extended-FoV.
# It will be overwritten later by the user-defined CoRs
overwrite_options={"reconstruction/rotation_axis_position": 10.0},
)
if reconstructor.delta_z > 1:
raise ValueError("Only slice reconstruction can be used (have delta_z = %d)" % reconstructor.delta_z)
reconstructor.reconstruct() # warm-up, spawn pipeline
pipeline = reconstructor.pipeline
file_prefix = pipeline.processing_options["save"]["file_prefix"]
#####
# Remove the first reconstructed file (not used here)
last_file = list(pipeline.writer.writer.browse_data_files())[-1]
try:
remove(last_file)
except:
pass
######
cors = get_user_cors(args["cor"])
all_recs = []
rec_instance = pipeline.reconstruction
for cor in cors:
# Re-configure with new CoR
pipeline.processing_options["reconstruction"]["rotation_axis_position"] = cor
pipeline.processing_options["save"]["file_prefix"] = file_prefix + "_%.03f" % cor
pipeline._init_writer(create_subfolder=False, single_output_file_initialized=False)
# Get sinogram into contiguous array
# TODO Can't do memcpy2D ?! It used to work in cuda 11.
# For now: transfer to host... not optimal
sino = pipeline._d_radios[:, pipeline._d_radios.shape[1] // 2, :].get() # pylint: disable=E1136
if pipeline.process_config.do_halftomo:
# re-initialize FBP object, because in half-tomography the output slice size is a function of CoR
options = pipeline.processing_options["reconstruction"]
rec_instance = pipeline.FBPClass(
sino.shape,
angles=options["angles"],
rot_center=cor,
filter_name=options["fbp_filter_type"] or "none",
halftomo=options["enable_halftomo"],
# slice_roi=self.process_config.rec_roi,
padding_mode=options["padding_type"],
extra_options={
"scale_factor": 1.0 / options["voxel_size_cm"][0],
"axis_correction": options["axis_correction"],
"centered_axis": options["centered_axis"],
"clip_outer_circle": options["clip_outer_circle"],
"filter_cutoff": options["fbp_filter_cutoff"],
},
)
else:
pipeline.reconstruction.reset_rot_center(cor)
# Run reconstruction
rec = rec_instance.fbp(sino)
# if return_all_recs:
# all_recs.append(rec)
rec_3D = view_as_images_stack(rec) # writer wants 3D data
# Write
pipeline.writer.write_data(rec_3D)
reconstructor.logger.info("Wrote %s" % pipeline.writer.fname)
return 0
if __name__ == "__main__":
main()