Commit 705a20e110fa4a1d90bbeb9c572078df820bf55a

Authored by okahilak
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:
... ...