Skip to content

Commit 2c45632

Browse files
Merge pull request #93 from arcadelab/dev
Dev
2 parents 846e701 + ae1bb9b commit 2c45632

File tree

7 files changed

+84
-97
lines changed

7 files changed

+84
-97
lines changed

deepdrr/annotations/line_annotation.py

+30-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import json
88
import pyvista as pv
99

10+
from .fiducials import FiducialList
1011
from .. import geo, utils
1112
from ..vol import Volume
1213

@@ -50,18 +51,16 @@ def __init__(
5051
self.endpoint = geo.point(endpoint)
5152
self.volume = volume
5253
if volume is None:
53-
assert (
54-
world_from_anatomical is not None
55-
and anatomical_coordinate_system.upper() in ["RAS", "LPS"]
56-
)
54+
assert world_from_anatomical is not None and anatomical_coordinate_system.upper() in [
55+
"RAS",
56+
"LPS",
57+
]
5758
self._anatomical_coordinate_system = anatomical_coordinate_system.upper()
5859
self._world_from_anatomical = geo.frame_transform(world_from_anatomical)
5960
else:
6061
self.volume = volume
6162

62-
assert (
63-
self.startpoint.dim == self.endpoint.dim
64-
), "annotation points must have matching dim"
63+
assert self.startpoint.dim == self.endpoint.dim, "annotation points must have matching dim"
6564

6665
def __str__(self):
6766
return f"LineAnnotation({self.startpoint}, {self.endpoint})"
@@ -93,8 +92,7 @@ def from_json(
9392

9493
if volume is None:
9594
assert (
96-
world_from_anatomical is not None
97-
and anatomical_coordinate_system is not None
95+
world_from_anatomical is not None and anatomical_coordinate_system is not None
9896
), "must supply the anatomical transform"
9997
else:
10098
anatomical_coordinate_system = volume.anatomical_coordinate_system
@@ -140,6 +138,25 @@ def from_json(
140138
def from_markup(cls, *args, **kwargs):
141139
return cls.from_json(*args, **kwargs)
142140

141+
@classmethod
142+
def from_fcsv(cls, path: Path, **kwargs) -> LineAnnotation:
143+
"""Load a LineAnnotation from a .fcsv file.
144+
145+
Args:
146+
path (Path): Path to the .fcsv file.
147+
world_from_anatomical (Optional[geo.FrameTransform], optional): The pose of the volume in world coordinates. Defaults to None.
148+
149+
Returns:
150+
LineAnnotation: The loaded annotation.
151+
"""
152+
fiducial_list = FiducialList.from_fcsv(path)
153+
assert len(fiducial_list) == 2, "fcsv file must contain exactly two points"
154+
return cls(
155+
fiducial_list[0],
156+
fiducial_list[1],
157+
**kwargs,
158+
)
159+
143160
def save(
144161
self,
145162
path: str,
@@ -287,6 +304,9 @@ def trajectory_in_world(self) -> geo.Vector3D:
287304
def direction_in_world(self) -> geo.Vector3D:
288305
return self.trajectory_in_world.normalized()
289306

307+
def get_direction(self) -> geo.Vector3D:
308+
return self.direction_in_world
309+
290310
def get_mesh(self):
291311
"""Get the mesh in anatomical coordinates."""
292312
u = self.startpoint
@@ -297,9 +317,7 @@ def get_mesh(self):
297317
mesh += pv.Sphere(2.5, v)
298318
return mesh
299319

300-
def get_mesh_in_world(
301-
self, full: bool = True, use_cached: bool = False
302-
) -> pv.PolyData:
320+
def get_mesh_in_world(self, full: bool = True, use_cached: bool = False) -> pv.PolyData:
303321
u = self.startpoint_in_world
304322
v = self.endpoint_in_world
305323

deepdrr/device/device.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ def get_mesh_in_world(self, full=False, use_cached=True):
188188
+ pv.Line(s, ur)
189189
+ pv.Line(s, bl)
190190
+ pv.Line(s, br)
191-
+ pv.Line(c, s)
192-
+ pv.Sphere(5, c)
191+
# + pv.Line(c, s) # Line along principle ray
192+
# + pv.Sphere(5, c) # Sphere in center of image.
193193
)
194194
mesh.transform(geo.get_data(self.world_from_camera3d), inplace=True)
195195
return mesh

deepdrr/projector/projector.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@
3434

3535
# import pycuda.autoinit # causes problems when running with pytorch concurrently
3636
import pycuda.driver as cuda
37-
from pycuda.autoinit import context
37+
38+
# from pycuda.autoinit import context # also causes problems
39+
from pycuda.autoprimaryctx import context # retains context across multiple calls
3840
from pycuda.compiler import SourceModule
3941
except ImportError:
4042
log.warning(f"Running without pycuda: projector operations will fail.")
43+
except RuntimeError as e:
44+
log.warning(f"Running without pycuda, possibly in subprocess: {e}")
4145

4246

4347
def import_pycuda():

deepdrr/utils/mesh_utils.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,12 @@ def voxelize(
147147
ijk_from_world = world_from_ijk.inv
148148

149149
data = np.zeros((x, y, z), dtype=np.uint8)
150-
for p in track(voxels.points, "Rasterizing..."):
151-
p = geo.point(p)
152-
ijk = ijk_from_world @ p
153-
i, j, k = np.array(ijk).astype(int)
154-
data[i, j, k] = 1
150+
vectors = np.array(voxels.points)
151+
A_h = np.hstack((vectors, np.ones((vectors.shape[0], 1))))
152+
transform = np.array(ijk_from_world)
153+
B = (transform @ A_h.T).T[:, :3]
154+
B = np.round(B).astype(int)
155+
data[B[:, 0], B[:, 1], B[:, 2]] = 1
155156

156157
return data, world_from_ijk
157158

deepdrr/vol/kwire.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
class KWire(Volume):
14-
_mesh_material = "titanium"
14+
_mesh_material = "iron"
1515

1616
diameter = 2.0 # mm
1717
tip_in_IJK: geo.Point3D
@@ -54,7 +54,7 @@ def from_example(
5454
Returns:
5555
KWire: The example KWire built into DeepDRR.
5656
"""
57-
url = "https://livejohnshopkins-my.sharepoint.com/:u:/g/personal/bkillee1_jh_edu/Ec2XGMXg_ItGtYWR_FfqHmUBwXJ1LmLBbbs4J_-3rJJQZg?e=fFWq6f&download=1"
57+
url = "https://livejohnshopkins-my.sharepoint.com/:u:/g/personal/bkillee1_jh_edu/ERoEsDbaFj9InktoRKnrT-MBSF2oCOrZ9uyOeWViRx4-Qg?e=s5fofv&download=1"
5858
md5 = "83ba7b63ebc0912d34ed5880460f81bd"
5959
filename = "Kwire2.nii.gz"
6060
path = data_utils.download(url, filename, md5=md5)

0 commit comments

Comments
 (0)