Commit c3593caae8f8e4d53e2ae83c18b80fe979ec98b3

Authored by Andrey Zhdanov
Committed by GitHub
1 parent 29f83106
Exists in master

Added versioning to markers file format (#331)

* fixed the code for save markers dialog (bug appearing on Linux), minor cleanup

* Legacy marker code (mks files) isolated

* Added support for marker file versions
Strings in marker files are now quoted
invesalius/constants.py
... ... @@ -803,5 +803,7 @@ TREKKER_CONFIG = {'seed_max': 1, 'step_size': 0.1, 'min_fod': 0.1, 'probe_qualit
803 803 'write_interval': 50, 'numb_threads': '', 'max_lenth': 200,
804 804 'min_lenth': 20, 'max_sampling_step': 100}
805 805  
  806 +MARKER_FILE_MAGICK_STRING = "INVESALIUS3_MARKER_FILE_"
  807 +CURRENT_MARKER_FILE_VERSION = 0
806 808 WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss") + "|" +\
807 809 _("Marker files (*.mks)|*.mks")
... ...
invesalius/gui/task_navigator.py
... ... @@ -1428,6 +1428,9 @@ class MarkersPanel(wx.Panel):
1428 1428  
1429 1429 self.marker_colour = const.MARKER_COLOUR
1430 1430 self.marker_size = const.MARKER_SIZE
  1431 +
  1432 + # Define CSV dialect for saving/loading markers
  1433 + csv.register_dialect('markers_dialect', delimiter='\t', quoting=csv.QUOTE_NONNUMERIC)
1431 1434  
1432 1435 # Change marker size
1433 1436 spin_size = wx.SpinCtrl(self, -1, "", size=wx.Size(40, 23))
... ... @@ -1676,23 +1679,18 @@ class MarkersPanel(wx.Panel):
1676 1679 def OnLoadMarkers(self, evt):
1677 1680 filename = dlg.ShowLoadSaveDialog(message=_(u"Load markers"),
1678 1681 wildcard=const.WILDCARD_MARKER_FILES)
1679   - # data_dir = os.environ.get('OneDrive') + r'\data\dti_navigation\baran\anat_reg_improve_20200609'
1680   - # marker_path = 'markers.mks'
1681   - # filename = os.path.join(data_dir, marker_path)
1682   -
1683   - if filename:
  1682 +
  1683 + def __legacy_load_markers(filename):
  1684 + """Code for loading markers in the old .mks format. To be deprecated at some point."""
1684 1685 try:
1685 1686 count_line = self.lc.GetItemCount()
1686   - # content = [s.rstrip() for s in open(filename)]
  1687 +
  1688 + # read lines from the file
1687 1689 with open(filename, 'r') as file:
1688 1690 reader = csv.reader(file, delimiter='\t')
1689   -
1690   - # skip the header
1691   - if filename.lower().endswith('.mkss'):
1692   - next(reader)
1693   -
1694 1691 content = [row for row in reader]
1695 1692  
  1693 + # parse the lines and update the markers list
1696 1694 for line in content:
1697 1695 target = None
1698 1696 if len(line) > 8:
... ... @@ -1746,6 +1744,62 @@ class MarkersPanel(wx.Panel):
1746 1744 count_line += 1
1747 1745 except:
1748 1746 wx.MessageBox(_("Invalid markers file."), _("InVesalius 3"))
  1747 +
  1748 + if not filename:
  1749 + return
  1750 +
  1751 + if filename.lower().endswith('.mks'):
  1752 + __legacy_load_markers(filename)
  1753 + return
  1754 +
  1755 + # Treat any extension othjer than .mks as 'new' format that has magick
  1756 + # string and version number
  1757 + try:
  1758 + count_line = self.lc.GetItemCount()
  1759 +
  1760 + with open(filename, 'r') as file:
  1761 + magick_line = file.readline()
  1762 + assert magick_line.startswith(const.MARKER_FILE_MAGICK_STRING)
  1763 + ver = int(magick_line.split('_')[-1])
  1764 + if ver != 0:
  1765 + wx.MessageBox(_("Unknown version of the markers file."), _("InVesalius 3"))
  1766 + return
  1767 +
  1768 + # read lines from the file
  1769 + reader = csv.reader(file, dialect='markers_dialect')
  1770 + next(reader) # skip the header line
  1771 + content = [row for row in reader]
  1772 +
  1773 + # parse the lines and update the markers list
  1774 + for line in content:
  1775 + target = None
  1776 +
  1777 + coord = [float(s) for s in line[:6]]
  1778 + colour = [float(s) for s in line[6:9]]
  1779 + size = float(line[9])
  1780 + marker_id = line[10]
  1781 +
  1782 + seed = [float(s) for s in line[11:14]]
  1783 +
  1784 + for i in const.BTNS_IMG_MARKERS:
  1785 + if marker_id in list(const.BTNS_IMG_MARKERS[i].values())[0]:
  1786 + Publisher.sendMessage('Load image fiducials', marker_id=marker_id, coord=coord)
  1787 + elif marker_id == 'TARGET':
  1788 + target = count_line
  1789 +
  1790 + target_id = line[14]
  1791 +
  1792 + self.CreateMarker(coord=coord, colour=colour, size=size,
  1793 + marker_id=marker_id, target_id=target_id, seed=seed)
  1794 +
  1795 + # if there are multiple TARGETS will set the last one
  1796 + if target:
  1797 + self.OnMenuSetTarget(target)
  1798 +
  1799 + count_line += 1
  1800 +
  1801 + except:
  1802 + wx.MessageBox(_("Invalid markers file."), _("InVesalius 3"))
1749 1803  
1750 1804 def OnMarkersVisibility(self, evt, ctrl):
1751 1805  
... ... @@ -1768,7 +1822,7 @@ class MarkersPanel(wx.Panel):
1768 1822 filename = dlg.ShowLoadSaveDialog(message=_(u"Save markers as..."),
1769 1823 wildcard=const.WILDCARD_MARKER_FILES,
1770 1824 style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
1771   - default_filename="markers.mks", save_ext="mks")
  1825 + default_filename=default_filename)
1772 1826  
1773 1827 header_titles = ['x', 'y', 'z', 'alpha', 'beta', 'gamma', 'r', 'g', 'b',
1774 1828 'size', 'marker_id', 'x_seed', 'y_seed', 'z_seed', 'target_id']
... ... @@ -1776,9 +1830,11 @@ class MarkersPanel(wx.Panel):
1776 1830 if filename:
1777 1831 if self.list_coord:
1778 1832 with open(filename, 'w', newline='') as file:
1779   - writer = csv.writer(file, delimiter='\t')
1780   -
1781   - if filename.lower().endswith('.mkss'):
  1833 + if filename.lower().endswith('.mks'):
  1834 + writer = csv.writer(file, delimiter='\t')
  1835 + else:
  1836 + file.writelines(['%s%i\n' % (const.MARKER_FILE_MAGICK_STRING, const.CURRENT_MARKER_FILE_VERSION)])
  1837 + writer = csv.writer(file, dialect='markers_dialect')
1782 1838 writer.writerow(header_titles)
1783 1839  
1784 1840 writer.writerows(self.list_coord)
... ...