Source code for pytomography.io.shared.interfile
from __future__ import annotations
from pathlib import Path
import numpy as np
import os
import re
import torch
import pytomography
[docs]def get_header_value(
list_of_attributes: list[str],
header: str,
dtype: type = np.float32,
split_substr = ':=',
split_idx = -1,
return_all = False
) -> float|str|int:
"""Finds the first entry in an Interfile with the string ``header``
Args:
list_of_attributes (list[str]): Simind data file, as a list of lines.
header (str): The header looked for
dtype (type, optional): The data type to be returned corresponding to the value of the header. Defaults to np.float32.
Returns:
float|str|int: The value corresponding to the header (header).
"""
header = header.replace('[', '\[').replace(']','\]').replace('(', '\(').replace(')', '\)')
y = np.vectorize(lambda y, x: bool(re.compile(x).search(y)))
selection = y(list_of_attributes, header).astype(bool)
lines = list_of_attributes[selection]
if len(lines)==0:
return False
values = []
for i, line in enumerate(lines):
if dtype == np.float32:
values.append(np.float32(line.replace('\n', '').split(split_substr)[split_idx]))
elif dtype == str:
values.append(line.replace('\n', '').split(split_substr)[split_idx].replace(' ', ''))
elif dtype == int:
values.append(int(line.replace('\n', '').split(split_substr)[split_idx].replace(' ', '')))
if not(return_all):
return values[0]
return values
[docs]def get_attenuation_map_interfile(headerfile: str):
"""Opens attenuation data from SIMIND output
Args:
headerfile (str): Path to header file
Returns:
torch.Tensor[batch_size, Lx, Ly, Lz]: Tensor containing attenuation map required for attenuation correction in SPECT/PET imaging.
"""
with open(headerfile) as f:
headerdata = f.readlines()
headerdata = np.array(headerdata)
matrix_size_1 = get_header_value(headerdata, 'matrix size [1]', int)
matrix_size_2 = get_header_value(headerdata, 'matrix size [2]', int)
matrix_size_3 = get_header_value(headerdata, 'matrix size [3]', int)
shape = (matrix_size_3, matrix_size_2, matrix_size_1)
imagefile = get_header_value(headerdata, 'name of data file', str)
amap = np.fromfile(os.path.join(str(Path(headerfile).parent), imagefile), dtype=np.float32)
# Flip "Z" ("X" in SIMIND) b/c "first density image located at +X" according to SIMIND manual
# Flip "Y" ("Z" in SIMIND) b/c axis convention is opposite for x22,5x (mu-castor format)
amap = np.transpose(amap.reshape(shape), (2,1,0))[:,::-1,::-1]
amap = torch.tensor(amap.copy()).unsqueeze(dim=0)
return amap.to(pytomography.device)