Commit 705a20e110fa4a1d90bbeb9c572078df820bf55a
Committed by
GitHub
1 parent
1560ae56
Exists in
master
UPD: Refactor markers in navigation (#321)
- New mkss file format with better structure - Create, save, load markers updated The changes mostly courtesy of vhosouza; I rebased them on top of the current main branch and did a few further changes.
Showing
1 changed file
with
79 additions
and
67 deletions
Show diff stats
invesalius/gui/task_navigator.py
... | ... | @@ -22,6 +22,7 @@ import csv |
22 | 22 | import os |
23 | 23 | import queue |
24 | 24 | import sys |
25 | +import time | |
25 | 26 | import threading |
26 | 27 | |
27 | 28 | import nibabel as nb |
... | ... | @@ -963,7 +964,13 @@ class NeuronavigationPanel(wx.Panel): |
963 | 964 | self.numctrls_fiducial[n][2].GetValue(), 0, 0, 0 |
964 | 965 | |
965 | 966 | Publisher.sendMessage('Set image fiducial', fiducial_name=fiducial_name, coord=coord[0:3]) |
966 | - Publisher.sendMessage('Create marker', coord=coord, marker_id=marker_id) | |
967 | + | |
968 | + colour = (0., 1., 0.) | |
969 | + size = 2 | |
970 | + seed = 3 * [0.] | |
971 | + | |
972 | + Publisher.sendMessage('Create marker', coord=coord, colour=colour, size=size, | |
973 | + marker_id=marker_id, seed=seed) | |
967 | 974 | else: |
968 | 975 | for m in [0, 1, 2]: |
969 | 976 | self.numctrls_fiducial[n][m].SetValue(float(self.current_coord[m])) |
... | ... | @@ -1447,7 +1454,7 @@ class MarkersPanel(wx.Panel): |
1447 | 1454 | Publisher.subscribe(self.UpdateCurrentCoord, 'Set cross focal point') |
1448 | 1455 | Publisher.subscribe(self.OnDeleteSingleMarker, 'Delete fiducial marker') |
1449 | 1456 | Publisher.subscribe(self.OnDeleteAllMarkers, 'Delete all markers') |
1450 | - Publisher.subscribe(self.OnCreateMarker, 'Create marker') | |
1457 | + Publisher.subscribe(self.CreateMarker, 'Create marker') | |
1451 | 1458 | Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status') |
1452 | 1459 | Publisher.subscribe(self.UpdateSeedCoordinates, 'Update tracts') |
1453 | 1460 | |
... | ... | @@ -1497,28 +1504,33 @@ class MarkersPanel(wx.Panel): |
1497 | 1504 | else: |
1498 | 1505 | id_label = dlg.ShowEnterMarkerID(self.lc.GetItemText(list_index, 4)) |
1499 | 1506 | if id_label == 'TARGET': |
1500 | - id_label = '' | |
1507 | + id_label = '*' | |
1501 | 1508 | wx.MessageBox(_("Invalid TARGET ID."), _("InVesalius 3")) |
1502 | - self.lc.SetItem(list_index, 4, id_label) | |
1509 | + | |
1503 | 1510 | # Add the new ID to exported list |
1504 | 1511 | if len(self.list_coord[list_index]) > 8: |
1505 | 1512 | self.list_coord[list_index][10] = str(id_label) |
1506 | 1513 | else: |
1507 | 1514 | self.list_coord[list_index][7] = str(id_label) |
1508 | 1515 | |
1516 | + self.lc.SetItem(list_index, 4, id_label) | |
1517 | + | |
1509 | 1518 | def OnMenuSetTarget(self, evt): |
1510 | 1519 | if isinstance(evt, int): |
1511 | 1520 | self.lc.Focus(evt) |
1512 | 1521 | |
1513 | 1522 | if self.tgt_flag: |
1523 | + marker_id = '*' | |
1524 | + | |
1514 | 1525 | self.lc.SetItemBackgroundColour(self.tgt_index, 'white') |
1515 | 1526 | Publisher.sendMessage('Set target transparency', status=False, index=self.tgt_index) |
1516 | - self.lc.SetItem(self.tgt_index, 4, '') | |
1527 | + self.lc.SetItem(self.tgt_index, 4, marker_id) | |
1528 | + | |
1517 | 1529 | # Add the new ID to exported list |
1518 | 1530 | if len(self.list_coord[self.tgt_index]) > 8: |
1519 | - self.list_coord[self.tgt_index][10] = str('') | |
1531 | + self.list_coord[self.tgt_index][10] = marker_id | |
1520 | 1532 | else: |
1521 | - self.list_coord[self.tgt_index][7] = str('') | |
1533 | + self.list_coord[self.tgt_index][7] = marker_id | |
1522 | 1534 | |
1523 | 1535 | self.tgt_index = self.lc.GetFocusedItem() |
1524 | 1536 | self.lc.SetItemBackgroundColour(self.tgt_index, 'RED') |
... | ... | @@ -1538,8 +1550,11 @@ class MarkersPanel(wx.Panel): |
1538 | 1550 | |
1539 | 1551 | if color_new: |
1540 | 1552 | assert len(color_new) == 3 |
1541 | - for n, col in enumerate(color_new): | |
1542 | - self.list_coord[index][n+6] = col/255.0 | |
1553 | + | |
1554 | + # XXX: Seems like a slightly too early point for rounding; better to round only when the value | |
1555 | + # is printed to the screen or file. | |
1556 | + # | |
1557 | + self.list_coord[index][6:9] = [round(s/255.0, 3) for s in color_new] | |
1543 | 1558 | |
1544 | 1559 | Publisher.sendMessage('Set new color', index=index, color=color_new) |
1545 | 1560 | |
... | ... | @@ -1604,23 +1619,7 @@ class MarkersPanel(wx.Panel): |
1604 | 1619 | Publisher.sendMessage('Remove marker', index=index) |
1605 | 1620 | |
1606 | 1621 | def OnCreateMarker(self, evt=None, coord=None, marker_id=None, colour=None): |
1607 | - # OnCreateMarker is used for both pubsub and button click events | |
1608 | - # Pubsub is used for markers created with fiducial buttons, trigger and create marker button | |
1609 | - if not colour: | |
1610 | - colour = self.marker_colour | |
1611 | - if not coord: | |
1612 | - coord = self.current_coord | |
1613 | - | |
1614 | - if evt is None: | |
1615 | - if coord: | |
1616 | - self.CreateMarker(coord=coord, colour=(0.0, 1.0, 0.0), size=self.marker_size, | |
1617 | - marker_id=marker_id, seed=self.current_seed) | |
1618 | - else: | |
1619 | - self.CreateMarker(coord=self.current_coord, colour=colour, size=self.marker_size, | |
1620 | - seed=self.current_seed) | |
1621 | - else: | |
1622 | - self.CreateMarker(coord=self.current_coord, colour=colour, size=self.marker_size, | |
1623 | - seed=self.current_seed) | |
1622 | + self.CreateMarker() | |
1624 | 1623 | |
1625 | 1624 | def OnLoadMarkers(self, evt): |
1626 | 1625 | filename = dlg.ShowLoadSaveDialog(message=_(u"Load markers"), |
... | ... | @@ -1635,50 +1634,63 @@ class MarkersPanel(wx.Panel): |
1635 | 1634 | # content = [s.rstrip() for s in open(filename)] |
1636 | 1635 | with open(filename, 'r') as file: |
1637 | 1636 | reader = csv.reader(file, delimiter='\t') |
1637 | + | |
1638 | + # skip the header | |
1639 | + if filename.lower().endswith('.mkss'): | |
1640 | + next(reader) | |
1641 | + | |
1638 | 1642 | content = [row for row in reader] |
1639 | 1643 | |
1640 | 1644 | for line in content: |
1641 | 1645 | target = None |
1642 | - # line = [s for s in data.split()] | |
1643 | 1646 | if len(line) > 8: |
1644 | 1647 | coord = [float(s) for s in line[:6]] |
1645 | 1648 | colour = [float(s) for s in line[6:9]] |
1646 | 1649 | size = float(line[9]) |
1647 | - # marker_id = line[10] | |
1650 | + marker_id = line[10] | |
1651 | + | |
1648 | 1652 | if len(line) > 11: |
1649 | 1653 | seed = [float(s) for s in line[11:14]] |
1650 | 1654 | else: |
1651 | - seed = 0., 0., 0. | |
1652 | - | |
1653 | - # coord = float(line[0]), float(line[1]), float(line[2]), float(line[3]), float(line[4]), float(line[5]) | |
1654 | - # colour = float(line[6]), float(line[7]), float(line[8]) | |
1655 | - # size = float(line[9]) | |
1655 | + seed = 3 * [0.] | |
1656 | 1656 | |
1657 | 1657 | if len(line) >= 11: |
1658 | 1658 | for i in const.BTNS_IMG_MARKERS: |
1659 | - if line[10] in list(const.BTNS_IMG_MARKERS[i].values())[0]: | |
1660 | - Publisher.sendMessage('Load image fiducials', marker_id=line[10], coord=coord) | |
1661 | - elif line[10] == 'TARGET': | |
1659 | + if marker_id in list(const.BTNS_IMG_MARKERS[i].values())[0]: | |
1660 | + Publisher.sendMessage('Load image fiducials', marker_id=marker_id, coord=coord) | |
1661 | + elif marker_id == 'TARGET': | |
1662 | 1662 | target = count_line |
1663 | 1663 | else: |
1664 | - line.append("") | |
1665 | - | |
1666 | - self.CreateMarker(coord, colour, size, line[10], seed) | |
1667 | - if target is not None: | |
1668 | - self.OnMenuSetTarget(target) | |
1664 | + marker_id = '*' | |
1669 | 1665 | |
1666 | + if len(line) == 15: | |
1667 | + target_id = line[14] | |
1668 | + else: | |
1669 | + target_id = '*' | |
1670 | 1670 | else: |
1671 | + # for compatibility with previous version without the extra seed and target columns | |
1671 | 1672 | coord = float(line[0]), float(line[1]), float(line[2]), 0, 0, 0 |
1672 | 1673 | colour = float(line[3]), float(line[4]), float(line[5]) |
1673 | 1674 | size = float(line[6]) |
1674 | 1675 | |
1676 | + seed = 3 * [0] | |
1677 | + target_id = '*' | |
1678 | + | |
1675 | 1679 | if len(line) == 8: |
1680 | + marker_id = line[7] | |
1676 | 1681 | for i in const.BTNS_IMG_MARKERS: |
1677 | - if line[7] in list(const.BTNS_IMG_MARKERS[i].values())[0]: | |
1678 | - Publisher.sendMessage('Load image fiducials', marker_id=line[7], coord=coord) | |
1682 | + if marker_id in list(const.BTNS_IMG_MARKERS[i].values())[0]: | |
1683 | + Publisher.sendMessage('Load image fiducials', marker_id=marker_id, coord=coord) | |
1679 | 1684 | else: |
1680 | - line.append("") | |
1681 | - self.CreateMarker(coord, colour, size, line[7]) | |
1685 | + marker_id = '*' | |
1686 | + | |
1687 | + self.CreateMarker(coord=coord, colour=colour, size=size, | |
1688 | + marker_id=marker_id, target_id=target_id, seed=seed) | |
1689 | + | |
1690 | + # if there are multiple TARGETS will set the last one | |
1691 | + if target: | |
1692 | + self.OnMenuSetTarget(target) | |
1693 | + | |
1682 | 1694 | count_line += 1 |
1683 | 1695 | except: |
1684 | 1696 | wx.MessageBox(_("Invalid markers file."), _("InVesalius 3")) |
... | ... | @@ -1693,32 +1705,31 @@ class MarkersPanel(wx.Panel): |
1693 | 1705 | ctrl.SetLabel('Hide') |
1694 | 1706 | |
1695 | 1707 | def OnSaveMarkers(self, evt): |
1708 | + prj_data = prj.Project() | |
1709 | + timestamp = time.localtime(time.time()) | |
1710 | + stamp_date = '{:0>4d}{:0>2d}{:0>2d}'.format(timestamp.tm_year, timestamp.tm_mon, timestamp.tm_mday) | |
1711 | + stamp_time = '{:0>2d}{:0>2d}{:0>2d}'.format(timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec) | |
1712 | + sep = '-' | |
1713 | + parts = [stamp_date, stamp_time, prj_data.name, 'markers'] | |
1714 | + default_filename = sep.join(parts) + '.mkss' | |
1715 | + | |
1696 | 1716 | filename = dlg.ShowLoadSaveDialog(message=_(u"Save markers as..."), |
1697 | 1717 | wildcard=const.WILDCARD_MARKER_FILES, |
1698 | 1718 | style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, |
1699 | 1719 | default_filename="markers.mks", save_ext="mks") |
1700 | 1720 | |
1721 | + header_titles = ['x', 'y', 'z', 'alpha', 'beta', 'gamma', 'r', 'g', 'b', | |
1722 | + 'size', 'marker_id', 'x_seed', 'y_seed', 'z_seed', 'target_id'] | |
1723 | + | |
1701 | 1724 | if filename: |
1702 | 1725 | if self.list_coord: |
1703 | 1726 | with open(filename, 'w', newline='') as file: |
1704 | 1727 | writer = csv.writer(file, delimiter='\t') |
1728 | + | |
1729 | + if filename.lower().endswith('.mkss'): | |
1730 | + writer.writerow(header_titles) | |
1731 | + | |
1705 | 1732 | writer.writerows(self.list_coord) |
1706 | - # text_file = open(filename, "w") | |
1707 | - # list_slice1 = self.list_coord[0] | |
1708 | - # coord = str('%.3f' %self.list_coord[0][0]) + "\t" + str('%.3f' %self.list_coord[0][1]) + "\t" + str('%.3f' %self.list_coord[0][2]) | |
1709 | - # angles = str('%.3f' %self.list_coord[0][3]) + "\t" + str('%.3f' %self.list_coord[0][4]) + "\t" + str('%.3f' %self.list_coord[0][5]) | |
1710 | - # properties = str('%.3f' %list_slice1[6]) + "\t" + str('%.3f' %list_slice1[7]) + "\t" + str('%.3f' %list_slice1[8]) + "\t" + str('%.1f' %list_slice1[9]) + "\t" + list_slice1[10] | |
1711 | - # line = coord + "\t" + angles + "\t" + properties + "\n" | |
1712 | - # list_slice = self.list_coord[1:] | |
1713 | - # | |
1714 | - # for value in list_slice: | |
1715 | - # coord = str('%.3f' %value[0]) + "\t" + str('%.3f' %value[1]) + "\t" + str('%.3f' %value[2]) | |
1716 | - # angles = str('%.3f' % value[3]) + "\t" + str('%.3f' % value[4]) + "\t" + str('%.3f' % value[5]) | |
1717 | - # properties = str('%.3f' %value[6]) + "\t" + str('%.3f' %value[7]) + "\t" + str('%.3f' %value[8]) + "\t" + str('%.1f' %value[9]) + "\t" + value[10] | |
1718 | - # line = line + coord + "\t" + angles + "\t" +properties + "\n" | |
1719 | - # | |
1720 | - # text_file.writelines(line) | |
1721 | - # text_file.close() | |
1722 | 1733 | |
1723 | 1734 | def OnSelectColour(self, evt, ctrl): |
1724 | 1735 | self.marker_colour = [colour/255.0 for colour in ctrl.GetValue()] |
... | ... | @@ -1726,7 +1737,12 @@ class MarkersPanel(wx.Panel): |
1726 | 1737 | def OnSelectSize(self, evt, ctrl): |
1727 | 1738 | self.marker_size = ctrl.GetValue() |
1728 | 1739 | |
1729 | - def CreateMarker(self, coord, colour, size, marker_id="x", seed=(0, 0, 0)): | |
1740 | + def CreateMarker(self, coord=None, colour=None, size=None, marker_id='*', target_id='*', seed=None): | |
1741 | + coord = coord or self.current_coord | |
1742 | + colour = colour or self.marker_colour | |
1743 | + size = size or self.marker_size | |
1744 | + seed = seed or self.current_seed | |
1745 | + | |
1730 | 1746 | # TODO: Use matrix coordinates and not world coordinates as current method. |
1731 | 1747 | # This makes easier for inter-software comprehension. |
1732 | 1748 | |
... | ... | @@ -1741,11 +1757,7 @@ class MarkersPanel(wx.Panel): |
1741 | 1757 | line.append(size) |
1742 | 1758 | line.append(marker_id) |
1743 | 1759 | line.extend(seed) |
1744 | - | |
1745 | - # line = [coord[0], coord[1], coord[2], coord[3], coord[4], coord[5], colour[0], colour[1], colour[2], size, marker_id] | |
1746 | - # line = [coord[0], coord[1], coord[2], coord[3], coord[4], coord[5], | |
1747 | - # colour[0], colour[1], colour[2], size, marker_id, | |
1748 | - # seed[0], seed[1], seed[2]] | |
1760 | + line.append(target_id) | |
1749 | 1761 | |
1750 | 1762 | # Adding current line to a list of all markers already created |
1751 | 1763 | if not self.list_coord: | ... | ... |