Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neuronavigation: Track multiple coils simultaneously and show stylus/probe #827

Merged
merged 44 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a802817
Aligned stylus.stl with VTK axes
Jul 10, 2024
7286afe
added r_change to navigation code, now add GUI to record r_change
Jul 11, 2024
147c5d6
StylusPage records coord_raw for Navigation
Jul 11, 2024
7dd3e61
Clean up corregistrate_probe
Jul 11, 2024
754b07f
using _ to discard the returned variable resulted in a wxPython error…
Jul 11, 2024
8e0ddb1
add illustration of how to align the stylus with head
Jul 11, 2024
a241a28
Reduce vertical gaps between GUI components. This has been tested on …
Jul 12, 2024
218ab9e
save stylus orientation (r_change) to config.json
Jul 12, 2024
929f3aa
Handle the case where manual stylus calibration is skipped. Print out…
Jul 12, 2024
e888ddf
Rename r_change to r_stylus (this is the rotation matrix to orient th…
Jul 18, 2024
8731817
Cleaning up, RUFF formatting
Jul 18, 2024
2a4ce4c
Completely replace corregistrate_dynamic by corregistrate_probe. Thes…
Jul 18, 2024
5e5271b
Refactor 'Track coil' button behavior: this determines (on the fly) w…
Jul 20, 2024
97b9bcd
Simplify how r_stylus is saved to file: move r_stylus to 'navigation'…
Jul 22, 2024
515c1bd
Remove behavior where probe is automatically shown/hidden when naviga…
Jul 23, 2024
9274b29
Now works with tracker coordinate system where stylus points in x-axi…
Jul 25, 2024
81f6da5
Start work on multicoil. Add n_coils variable to tracker connection i…
Jul 23, 2024
d997842
Larger refactor.
Jul 23, 2024
d215fff
Cleaning up.
Aug 12, 2024
d47431e
Added a warning before overwriting old coil registrations, other mino…
Aug 14, 2024
1ad1eb9
Remove icp_queue (which was only used in CoordinateCorregistrate thre…
Aug 16, 2024
6f6a950
Maximize viewer volume when target mode is set. Remove obsolete funct…
Aug 18, 2024
23606da
Minor fixes to ensure target mode works as normal with a single coil
Aug 18, 2024
efcf2af
Update PolarisCoord to receive multiple coil coordinates. Improve Pol…
Aug 20, 2024
6e09feb
Rotate stylus NT-115.rom to point in x-axis. Restore NBSref.rom to ol…
Aug 22, 2024
120869f
Reset tracker connection when n_coils is changed. This is necessary f…
Aug 22, 2024
7df6426
Clean comments and RUFF format
Aug 22, 2024
6f4c7dd
Add popup-menu to show/hide specific coil. Menu is shown when the Sho…
Aug 25, 2024
5a7ec8e
Specify which coil is connected to the robot. Add a check that robot.…
Aug 26, 2024
af8646e
Change GUI to its old form for single coil mode
Aug 28, 2024
694f954
Save/load robot coil name (the coil attached to robot) to config file…
Aug 29, 2024
9621084
Improve preferences wording and layout. Simplified LoadConfig. Remove…
Aug 31, 2024
9ac50ee
Add getter for robot coil name. Remove unused neuronavigation_api var…
Aug 31, 2024
0b49e17
Show/hide robot coil combobox when robot is connected/disconnected. R…
Sep 1, 2024
238073e
Minor fix
Sep 5, 2024
733dbe5
Minor change to improve code readability
Sep 5, 2024
64dcc18
Hide name box during coil registration if in single coil mode
Sep 5, 2024
2cf1133
Fix stylus orientation. The issue was that the vtk y-axis is flipped.
Sep 6, 2024
e222056
Before this commit, the stylus was correctly oriented with MRI heads.…
Sep 9, 2024
b15cb29
Add check to prevent delayed rendering of coil/probe when navigating.…
Sep 10, 2024
43160da
Show coil center/target even when coil is hidden. Handle exceptions w…
Sep 11, 2024
a9a5a9b
Remove incomplete robot check that causes bug with single robot
Sep 11, 2024
a5699ee
FIX: tracker device polhemus
rmatsuda Sep 30, 2024
f30bd29
Ruff
rmatsuda Sep 30, 2024
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
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies:
- pyclaron
- polhemusFT
- polhemus
- pypolaris==0.0.7
- pypolaris==0.0.8
- scikit-image==0.24.0
- scikit-learn==1.5.0
- torch==2.3.1
Expand Down
Binary file added icons/align.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icons/stylus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 7 additions & 12 deletions invesalius/data/bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,7 @@ def calculate_fre(

dist = np.zeros([3, 1])
for i in range(0, 6, 2):
p_m, _ = dcr.corregistrate_dynamic(
(m_change, 0), fiducials_raw[i : i + 2], ref_mode_id, icp
)
p_m, _ = dcr.corregistrate_probe(m_change, None, fiducials_raw[i : i + 2], ref_mode_id, icp)
dist[int(i / 2)] = np.sqrt(np.sum(np.power((p_m[:3] - fiducials[int(i / 2), :]), 2)))

return float(np.sqrt(np.sum(dist**2) / 3))
Expand Down Expand Up @@ -176,15 +174,15 @@ def calculate_fre(
def transform_icp(m_img: np.ndarray, m_icp: np.ndarray) -> np.ndarray:
coord_img = [m_img[0, -1], -m_img[1, -1], m_img[2, -1], 1]
m_img[0, -1], m_img[1, -1], m_img[2, -1], _ = m_icp @ coord_img
m_img[0, -1], m_img[1, -1], m_img[2, -1] = m_img[0, -1], -m_img[1, -1], m_img[2, -1]
m_img[1, -1] = -m_img[1, -1]

return m_img


def inverse_transform_icp(m_img: np.ndarray, m_icp: np.ndarray) -> np.ndarray:
coord_img = [m_img[0, -1], -m_img[1, -1], m_img[2, -1], 1]
m_img[0, -1], m_img[1, -1], m_img[2, -1], _ = np.linalg.inv(m_icp) @ coord_img
m_img[0, -1], m_img[1, -1], m_img[2, -1] = m_img[0, -1], -m_img[1, -1], m_img[2, -1]
m_img[1, -1] = -m_img[1, -1]

return m_img

Expand Down Expand Up @@ -212,19 +210,16 @@ def object_registration(
fids_raw[ic, :] = dco.dynamic_reference_m2(coords[ic, :], coords[3, :])[:3]

# compute initial alignment of probe fixed in the object in source frame

# XXX: Some duplicate processing is done here: the Euler angles are calculated once by
# the lines below, and then again in dco.coordinates_to_transformation_matrix.
#
a, b, g = np.radians(coords[3, 3:])
r_s0_raw = tr.euler_matrix(a, b, g, axes="rzyx")

s0_raw = dco.coordinates_to_transformation_matrix(
position=coords[3, :3],
orientation=coords[3, 3:],
axes="rzyx",
)

# copy rotation submatrix from s0_raw
r_s0_raw = np.eye(4)
r_s0_raw[:3, :3] = s0_raw[:3, :3]

# compute change of basis for object fiducials in source frame
base_obj_raw, q_obj_raw = base_creation(fids_raw[:3, :3])
r_obj_raw = np.identity(4)
Expand Down
22 changes: 14 additions & 8 deletions invesalius/data/coordinates.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,17 @@ def PolarisCoord(tracker_connection: "TrackerConnection", tracker_id: int, ref_m
trans_ref = np.array(ref[6:9]).astype(float)
coord2 = np.hstack((trans_ref, angles_ref))

obj = trck.obj.decode(const.FS_ENCODE).split(",")
angles_obj = np.degrees(tr.euler_from_quaternion(obj[2:6], axes="rzyx"))
trans_obj = np.array(obj[6:9]).astype(float)
coord3 = np.hstack((trans_obj, angles_obj))
obj_coords = []
for i in range(trck.objs.size()):
obj = trck.objs[i].decode(const.FS_ENCODE).split(",")
angles_obj = np.degrees(tr.euler_from_quaternion(obj[2:6], axes="rzyx"))
trans_obj = np.array(obj[6:9]).astype(float)
obj_coords.append(np.hstack((trans_obj, angles_obj)))

coord = np.vstack([coord1, coord2, coord3])
coord = np.vstack([coord1, coord2, *obj_coords])
marker_visibilities = [trck.probeID, trck.refID] + list(trck.objIDs)

return coord, [trck.probeID, trck.refID, trck.objID]
return coord, marker_visibilities


def CameraCoord(tracker_connection: "TrackerConnection", tracker_id: int, ref_mode):
Expand Down Expand Up @@ -538,6 +541,9 @@ def DebugCoordRandom(tracker_connection: "TrackerConnection", tracker_id: int, r
coord4 = np.array(
[uniform(*dx), uniform(*dx), uniform(*dx), uniform(*dt), uniform(*dt), uniform(*dt)]
)
coord5 = np.array(
[uniform(*dx), uniform(*dx), uniform(*dx), uniform(*dt), uniform(*dt), uniform(*dt)]
)

sleep(0.15)

Expand All @@ -555,9 +561,9 @@ def DebugCoordRandom(tracker_connection: "TrackerConnection", tracker_id: int, r

# Always make the markers visible when using debug tracker; this enables registration, as it
# is not possible to registering without markers.
marker_visibilities = [True, True, True]
marker_visibilities = [True, True, True, True, True]

return np.vstack([coord1, coord2, coord3, coord4]), marker_visibilities
return np.vstack([coord1, coord2, coord3, coord4, coord5]), marker_visibilities


def coordinates_to_transformation_matrix(
Expand Down
Loading
Loading