Browse Source

added script `unite-freesurfer-surfaces`

Fabian Peter Hammerle 1 year ago
parent
commit
356eb12cbd
3 changed files with 71 additions and 3 deletions
  1. 21 1
      freesurfer_surface/__main__.py
  2. 1 0
      setup.py
  3. 49 2
      tests/test_main.py

+ 21 - 1
freesurfer_surface/__main__.py

@@ -2,7 +2,7 @@ import argparse
 import csv
 import sys
 
-from freesurfer_surface import Annotation
+from freesurfer_surface import Annotation, Surface
 
 
 def annotation_labels():
@@ -21,3 +21,23 @@ def annotation_labels():
     csv_writer.writerow(('index', 'color', 'name'))
     labels = sorted(annotation.labels.values(), key=lambda l: l.index)
     csv_writer.writerows((l.index, l.hex_color_code, l.name,) for l in labels)
+
+
+def unite_surfaces():
+    """
+    Unite Multiple Surfaces in Freesurfer's TriangularSurface Format
+    Into a Single TriangularSurface File (i.e., lh.pial, lh.white)
+    """
+    argparser = argparse.ArgumentParser(
+        description=unite_surfaces.__doc__.strip())
+    argparser.add_argument('--output',
+                           metavar='OUTPUT_PATH',
+                           dest='output_path',
+                           required=True)
+    argparser.add_argument('input_paths',
+                           metavar='INPUT_PATH',
+                           nargs='+')
+    args = argparser.parse_args()
+    union = Surface.unite(Surface.read_triangular(p)
+                          for p in args.input_paths)
+    union.write_triangular(args.output_path)

+ 1 - 0
setup.py

@@ -44,6 +44,7 @@ setuptools.setup(
     entry_points={
         'console_scripts': [
             'freesurfer-annotation-labels = freesurfer_surface.__main__:annotation_labels',
+            'unite-freesurfer-surfaces = freesurfer_surface.__main__:unite_surfaces',
         ],
     },
     python_requires='>=3.5',

+ 49 - 2
tests/test_main.py

@@ -4,9 +4,12 @@ import subprocess
 import typing
 import unittest.mock
 
-from freesurfer_surface.__main__ import annotation_labels
+import numpy
 
-from conftest import ANNOTATION_FILE_PATH
+from freesurfer_surface import Surface, Triangle, Vertex
+from freesurfer_surface.__main__ import annotation_labels, unite_surfaces
+
+from conftest import ANNOTATION_FILE_PATH, SURFACE_FILE_PATH
 
 
 def check_rows(csv_rows: typing.List[str]):
@@ -39,3 +42,47 @@ def test_annotation_labels_script():
     assert not proc_info.stderr
     check_rows(list(csv.reader(io.StringIO(proc_info.stdout.decode()),
                                delimiter='\t')))
+
+
+def test_unite_surfaces_function(tmpdir, capsys):
+    surface_b = Surface.read_triangular(SURFACE_FILE_PATH)
+    surface_b.vertices = []
+    for i in range(5):
+        surface_b.add_vertex(Vertex(i, i, i))
+    surface_b.triangles = [Triangle((0, 1, 3)), Triangle((1, 3, 4))]
+    surface_b_path = tmpdir.join('b').strpath
+    surface_b.write_triangular(surface_b_path)
+    output_path = tmpdir.join('output_path').strpath
+    with unittest.mock.patch('sys.argv', ['', '--output', output_path,
+                                          SURFACE_FILE_PATH, surface_b_path]):
+        unite_surfaces()
+    out, err = capsys.readouterr()
+    assert not out
+    assert not err
+    union = Surface.read_triangular(output_path)
+    assert len(union.vertices) == 155627
+    assert len(union.triangles) == 311242
+    assert numpy.allclose(union.vertices[-5:], surface_b.vertices)
+
+
+def test_unite_surfaces_script(tmpdir):
+    surface_b = Surface.read_triangular(SURFACE_FILE_PATH)
+    surface_b.vertices = []
+    for i in range(5):
+        surface_b.add_vertex(Vertex(i, i, i))
+    surface_b.triangles = [Triangle((0, 1, 3)), Triangle((1, 3, 4))]
+    surface_b_path = tmpdir.join('b').strpath
+    surface_b.write_triangular(surface_b_path)
+    output_path = tmpdir.join('output_path').strpath
+    proc_info = subprocess.run(['unite-freesurfer-surfaces',
+                                '--output', output_path,
+                                SURFACE_FILE_PATH, surface_b_path,
+                                surface_b_path],
+                               check=True,
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE)
+    assert not proc_info.stdout
+    assert not proc_info.stderr
+    union = Surface.read_triangular(output_path)
+    assert len(union.vertices) == 155622 + (5 * 2)
+    assert len(union.triangles) == 311240 + (2 * 2)