diff --git a/mu_map/recon/project.py b/mu_map/recon/project.py index 9a4901dd3943a7c46c3c471ae29e103dee98954b..1ecea73711e45ae055897d22d99a6830bd8859b7 100644 --- a/mu_map/recon/project.py +++ b/mu_map/recon/project.py @@ -7,9 +7,10 @@ from pydicom.dataset import FileDataset as DCMImage import stir from mu_map.file.interfile import ( + Interfile, + InterfileKeys, load_interfile, write_interfile, - InterfileKeys, ) @@ -27,8 +28,8 @@ type of data := Tomographic imagedata byte order := LITTLEENDIAN number format := float number of bytes per pixel := 4 -patient orientation := feet_in -patient rotation := supine +patient orientation := {PATIENT_ORIENTATION} +patient rotation := {PATIENT_ROTATION} SPECT STUDY (General) := ;matrix axis label [2] := axial coordinate @@ -52,21 +53,18 @@ END OF INTERFILE := def forward_project( - recon_header: Dict[str, str], - recon_img: np.ndarray, + recon: Interfile, n_slices: Optional[int] = None, n_bins: Optional[int] = None, n_projections: int = 120, rotation: int = 360, start_angle: int = 180, radius: int = 150, - **kwargs, -) -> Tuple[Dict[str, str], np.ndarray]: +) -> Interfile: """ Forward project a reconstruction in INTERFILE format. - :param recon_header: the header of the reconstruction - :param recon_img: the reconstruction image + :param recon: the reconstruction in Interfile format :param n_slices: the number of slices of the projection - defaults to the number of slices of the reconstruction :param n_bins: the number of bins of the projection - defaults to the number of rows in the reconstruction :param n_projections: the number of views used for the projection @@ -75,6 +73,8 @@ def forward_project( :param radius: the radius of the detector circle in mm :return: an interfile image as a tuple of a header and a numpy array """ + recon_header, recon_img = recon + n_slices = recon_img.shape[0] if n_slices is None else n_slices n_bins = recon_img.shape[1] if n_bins is None else n_bins # work around a bug in STIR with start_angle = 0 @@ -89,12 +89,22 @@ def forward_project( header_proj = TEMPLATE_HEADER_PROJ.replace("{DATA_FILE}", filename_proj_data) header_proj = header_proj.replace("{SLICES}", str(n_slices)) header_proj = header_proj.replace("{BINS}", str(n_bins)) - header_proj = header_proj.replace("{SPACING_SLICES}", recon_header[InterfileKeys.spacing(3)]) - header_proj = header_proj.replace("{SPACING_BINS}", recon_header[InterfileKeys.spacing(1)]) + header_proj = header_proj.replace( + "{SPACING_SLICES}", recon_header[InterfileKeys.spacing(3)] + ) + header_proj = header_proj.replace( + "{SPACING_BINS}", recon_header[InterfileKeys.spacing(1)] + ) header_proj = header_proj.replace("{N_PROJECTIONS}", str(n_projections)) header_proj = header_proj.replace("{ROTATION}", str(rotation)) header_proj = header_proj.replace("{START_ANGLE}", str(start_angle)) header_proj = header_proj.replace("{RADIUS}", str(radius)) + header_proj = header_proj.replace( + "{PATIENT_ORIENTATION}", recon_header[InterfileKeys.patient_orientation] + ) + header_proj = header_proj.replace( + "{PATIENT_ROTATION}", recon_header[InterfileKeys.patient_rotation] + ) header_proj = header_proj.strip() # write temporary files to configure the projection with STIR @@ -107,7 +117,7 @@ def forward_project( f.write(header_proj) with open(os.path.join(dir_tmp.name, filename_proj_data), mode="wb") as f: f.write(b"") - write_interfile(filename_recon, recon_header, recon_img) + write_interfile(filename_recon, recon) projdata = stir.ProjData.read_from_file(filename_proj_header) recon = stir.FloatVoxelsOnCartesianGrid.read_from_file(filename_recon) @@ -177,6 +187,13 @@ if __name__ == "__main__": stir.Verbosity_set(args.verbosity) - header, image = load_as_interfile(args.recon) - header, image = forward_project(header, image, **vars(args)) - write_interfile(args.out, header, image) + recon = load_as_interfile(args.recon) + projection = forward_project( + recon, + n_slices=args.n_slices, + n_projections=args.n_projections, + rotation=args.rotation, + start_angle=args.start_angle, + radius=args.radius, + ) + write_interfile(args.out, projection)