Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 0 additions & 37 deletions .clang-format

This file was deleted.

4 changes: 0 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
[submodule "PETSIRD"]
path = PETSIRD
url = https://github.com/ETSInitiative/PETSIRD
branch=main
1 change: 0 additions & 1 deletion PETSIRD
Submodule PETSIRD deleted from ae3a04
19 changes: 3 additions & 16 deletions environment.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
name: petsird
name: petsird-visualisation
channels:
- conda-forge
- defaults
dependencies:
- bash-completion>=2.11
- cmake>=3.21.3
- fmt>=8.1.1
- compilers
- h5py>=3.7.0
- hdf5>=1.12.1
- howardhinnant_date>=3.0.1
- petsird=0.7
- ipykernel>=6.19.2
- ninja>=1.11.0
- nlohmann_json>=3.11.2
- numpy>=1.24.3
- python>=3.11.3
- matplotlib
- shellcheck>=0.8.0
- xtensor-fftw>=0.2.5
- xtensor>=0.24.2
- trimesh
124 changes: 38 additions & 86 deletions python/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import numpy as np
import numpy.typing as npt
import petsird
import petsird.helpers.geometry
import trimesh
import argparse

Expand All @@ -39,59 +40,6 @@
#########################################################################################
# Methods
#########################################################################################
def transform_to_mat44(
transform: petsird.RigidTransformation,
) -> npt.NDArray[np.float32]:
return np.vstack([transform.matrix, [0, 0, 0, 1]])


def mat44_to_transform(mat: npt.NDArray[np.float32]) -> petsird.RigidTransformation:
return petsird.RigidTransformation(matrix=mat[0:3, :])


def coordinate_to_homogeneous(coord: petsird.Coordinate) -> npt.NDArray[np.float32]:
return np.hstack([coord.c, 1])


def homogeneous_to_coordinate(
hom_coord: npt.NDArray[np.float32],
) -> petsird.Coordinate:
return petsird.Coordinate(c=hom_coord[0:3])


def mult_transforms(
transforms: list[petsird.RigidTransformation],
) -> petsird.RigidTransformation:
"""multiply rigid transformations"""
mat = np.array(
((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)),
dtype="float32",
)

for t in reversed(transforms):
mat = np.matmul(transform_to_mat44(t), mat)
return mat44_to_transform(mat)


def mult_transforms_coord(
transforms: list[petsird.RigidTransformation], coord: petsird.Coordinate
) -> petsird.Coordinate:
"""apply list of transformations to coordinate"""
# TODO better to multiply with coordinates in sequence, as first multiplying the matrices
hom = np.matmul(
transform_to_mat44(mult_transforms(transforms)),
coordinate_to_homogeneous(coord),
)
return homogeneous_to_coordinate(hom)


def transform_BoxShape(
transform: petsird.RigidTransformation, box_shape: petsird.BoxShape
) -> petsird.BoxShape:
return petsird.BoxShape(
corners=[mult_transforms_coord([transform], c) for c in box_shape.corners]
)


def create_box_from_vertices(vertices):
# Define faces using the indices of vertices that make up each face
Expand Down Expand Up @@ -120,43 +68,43 @@ def extract_detector_eff(show_det_eff, header):
if not show_det_eff:
return None

if header.scanner.detection_efficiencies.det_el_efficiencies is None:
eff = header.scanner.detection_efficiencies.detection_bin_efficiencies
if eff is None:
raise ValueError(
"The scanner detection efficiencies are not defined. Correct this or remove the show_det_eff flag."
)
return header.scanner.detection_efficiencies.det_el_efficiencies
return eff


def set_detector_color(det_mesh, detector_efficiencies, mod_i, num_det_in_module, det_i, random_color):
def set_detector_color(det_mesh, detector_efficiencies, type_of_module, num_modules, mod_i, num_det_in_module, det_i, random_color):
if random_color == True:
color = np.random.randint(0, 255, size=3)
elif detector_efficiencies is not None:
color = (crystal_color * detector_efficiencies[mod_i * num_det_in_module + det_i])
eff = np.reshape(detector_efficiencies[type_of_module], shape=(num_modules, num_det_in_module, -1))
color = (crystal_color * np.mean(eff[mod_i, det_i, :]))
else:
color = crystal_color

f_color = np.array([color[0], color[1], color[2], 50]).astype(
np.uint8
)

print(f_color)
det_mesh.visual.face_colors = f_color

return det_mesh



def set_module_color(
module_mesh, detector_efficiencies, mod_i, num_det_in_module, det_el, random_color
module_mesh, detector_efficiencies, type_of_module, num_modules, mod_i, num_det_in_module, random_color
):
if random_color == True:
color = np.random.randint(0, 255, size=3)
elif detector_efficiencies is not None:
# Mean of the detector efficiency in the current module
# Mean of the detector efficiencies in the current module
eff = np.reshape(detector_efficiencies[type_of_module], shape=(num_modules, num_det_in_module, -1))
color = crystal_color * np.mean(
detector_efficiencies.reshape((-1, len(det_el) * num_det_in_module))[
mod_i, :
]
)
eff[mod_i, :, :])
else:
color = crystal_color

Expand All @@ -177,8 +125,10 @@ def create_mesh(header, modules_only=False, show_det_eff=False, random_color=Fal
shapes = []
# draw all crystals
module_count = 0
for rep_module in header.scanner.scanner_geometry.replicated_modules:
det_el = (
for type_of_module in range(len(header.scanner.scanner_geometry.replicated_modules)):
rep_module = header.scanner.scanner_geometry.replicated_modules[type_of_module]
num_modules = len(rep_module.transforms)
det_els = (
rep_module.object.detecting_elements
) # Get all the detecting elements modules
for mod_i in range(len(rep_module.transforms)):
Expand All @@ -188,36 +138,38 @@ def create_mesh(header, modules_only=False, show_det_eff=False, random_color=Fal

vertices = [] # If showing modules only
mod_transform = rep_module.transforms[mod_i]
for rep_volume in det_el:
num_det_in_module = len(rep_volume.transforms)
for det_i in range(num_det_in_module):
transform = rep_volume.transforms[det_i]
box: petsird.BoxShape = transform_BoxShape(
mult_transforms([mod_transform, transform]),
rep_volume.object.shape,
)
corners = []
for boxcorner in box.corners:
corners.append(boxcorner.c)
if not modules_only:
det_mesh = create_box_from_vertices(corners)
num_det_in_module = len(det_els.transforms)
for det_i in range(num_det_in_module):
transform = det_els.transforms[det_i]
box: petsird.BoxShape = petsird.helpers.geometry.transform_BoxShape(
petsird.helpers.geometry.mult_transforms(
[mod_transform, transform]),
det_els.object.shape,
)
corners = []
for boxcorner in box.corners:
corners.append(boxcorner.c)

if not modules_only:
det_mesh = create_box_from_vertices(corners)

det_mesh = set_detector_color(det_mesh, detector_efficiencies, mod_i, num_det_in_module, det_i, random_color)
det_mesh = set_detector_color(det_mesh, detector_efficiencies, type_of_module, num_modules, mod_i, num_det_in_module, det_i, random_color)

shapes.append(det_mesh)
else:
vertices.append(corners)
shapes.append(det_mesh)
else:
vertices.append(corners)
if modules_only:
vertices_reshaped = np.array(vertices).reshape((-1, 3))
module_mesh = trimesh.convex.convex_hull(vertices_reshaped)

module_mesh = set_module_color(
module_mesh,
detector_efficiencies,
type_of_module,
num_modules,
mod_i,
num_det_in_module,
det_el, random_color
random_color
)

shapes.append(module_mesh)
Expand Down Expand Up @@ -312,7 +264,7 @@ def parserCreator():
file = sys.stdin.buffer
else:
file = open(args.input, "rb")
output_fname = args.output
output_fname = args.output

with petsird.BinaryPETSIRDReader(file) as reader:
header = reader.read_header()
Expand Down