Ejemplo n.º 1
0
    def test_surf_gifti(self, fn):
            # From section 14.4 in GIFTI Surface Data Format Version 1.0
            # (with some adoptions)

            test_data = '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE GIFTI SYSTEM "http://www.nitrc.org/frs/download.php/1594/gifti.dtd">
<GIFTI
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://www.nitrc.org/frs/download.php/1303/GIFTI_Caret.xsd"
  Version="1.0"
  NumberOfDataArrays="2">
<MetaData>
  <MD>
    <Name><![CDATA[date]]></Name>
    <Value><![CDATA[Thu Nov 15 09:05:22 2007]]></Value>
  </MD>
</MetaData>
<LabelTable/>
<DataArray Intent="NIFTI_INTENT_POINTSET"
  DataType="NIFTI_TYPE_FLOAT32"
  ArrayIndexingOrder="RowMajorOrder"
  Dimensionality="2"
  Dim0="4"
  Dim1="3"
  Encoding="ASCII"
  Endian="LittleEndian"
  ExternalFileName=""
  ExternalFileOffset="">
<CoordinateSystemTransformMatrix>
  <DataSpace><![CDATA[NIFTI_XFORM_TALAIRACH]]></DataSpace>
  <TransformedSpace><![CDATA[NIFTI_XFORM_TALAIRACH]]></TransformedSpace>
  <MatrixData>
    1.000000 0.000000 0.000000 0.000000
    0.000000 1.000000 0.000000 0.000000
    0.000000 0.000000 1.000000 0.000000
    0.000000 0.000000 0.000000 1.000000
  </MatrixData>
</CoordinateSystemTransformMatrix>
<Data>
  10.5 0 0
  0 20.5 0
  0 0 30.5
  0 0 0
</Data>
</DataArray>
<DataArray Intent="NIFTI_INTENT_TRIANGLE"
  DataType="NIFTI_TYPE_INT32"
  ArrayIndexingOrder="RowMajorOrder"
  Dimensionality="2"
  Dim0="4"
  Dim1="3"
  Encoding="ASCII"
  Endian="LittleEndian"
  ExternalFileName="" ExternalFileOffset="">
<Data>
0 1 2
1 2 3
0 1 3
0 2 3
</Data>
</DataArray>
</GIFTI>'''

            with open(fn, 'w') as f:
                f.write(test_data)

            # test I/O
            s = surf.read(fn)
            surf.write(fn, s)
            s = surf.read(fn)

            v = np.zeros((4, 3))
            v[0, 0] = 10.5
            v[1, 1] = 20.5
            v[2, 2] = 30.5

            f = np.asarray([[0, 1, 2], [1, 2, 3], [0, 1, 3], [0, 2, 3]],
                            dtype=np.int32)

            assert_array_equal(s.vertices, v)
            assert_array_equal(s.faces, f)
Ejemplo n.º 2
0
    def test_surf(self, temp_fn):
        """Some simple testing with surfaces
        """

        s = surf.generate_sphere(10)

        assert_true(s.nvertices == 102)
        assert_true(s.nfaces == 200)

        v = s.vertices
        f = s.faces

        assert_true(v.shape == (102, 3))
        assert_true(f.shape == (200, 3))

        # another surface
        t = s * 10 + 2
        assert_true(t.same_topology(s))
        assert_array_equal(f, t.faces)

        assert_array_equal(v * 10 + 2, t.vertices)

        # allow updating, but should not affect original array
        # CHECKME: maybe we want to throw an exception instead
        assert_true((v * 10 + 2 == t.vertices).all().all())
        assert_true((s.vertices * 10 + 2 == t.vertices).all().all())

        # a few checks on vertices and nodes
        v_check = {40:(0.86511144 , -0.28109175, -0.41541501),
                   10:(0.08706015, -0.26794358, -0.95949297)}
        f_check = {10:(7, 8, 1), 40:(30, 31, 21)}


        vf_checks = [(v_check, lambda x:x.vertices),
                     (f_check, lambda x:x.faces)]

        eps = .0001
        for cmap, f in vf_checks:
            for k, v in cmap.iteritems():
                surfval = f(s)[k, :]
                assert_true((abs(surfval - v) < eps).all())

        # make sure same topology fails with different topology
        u = surf.generate_cube()
        assert_false(u.same_topology(s))

        # check that neighbours are computed correctly
        # even if we nuke the topology afterwards
        for _ in [0, 1]:
            nbrs = s.neighbors
            n_check = [(0, 96, 0.284629),
                       (40, 39, 0.56218349),
                       (100, 99, 0.1741202)]
            for i, j, k in n_check:
                assert_true(abs(nbrs[i][j] - k) < eps)


        def assign_zero(x):
            x.faces[:, :] = 0
            return None

        assert_raises((ValueError, RuntimeError), assign_zero, s)

        # see if mapping to high res works
        h = surf.generate_sphere(40)

        low2high = s.map_to_high_resolution_surf(h, .1)
        partmap = {7: 141, 8: 144, 9: 148, 10: 153, 11: 157, 12: 281}
        for k, v in partmap.iteritems():
            assert_true(low2high[k] == v)

        # ensure that slow implementation gives same results as fast one
        low2high_slow = s.map_to_high_resolution_surf(h, .1)
        for k, v in low2high.iteritems():
            assert_true(low2high_slow[k] == v)

        #  should fail if epsilon is too small
        assert_raises(ValueError,
                      lambda x:x.map_to_high_resolution_surf(h, .01), s)

        n2f = s.node2faces
        for i in xrange(s.nvertices):
            nf = [10] if i < 2 else [5, 6] # number of faces expected

            assert_true(len(n2f[i]) in nf)


        # test dijkstra distances
        ds2 = s.dijkstra_distance(2)
        some_ds = {0: 3.613173280799, 1: 0.2846296765, 2: 0.,
                 52: 1.87458018, 53: 2.0487004817, 54: 2.222820777,
                 99: 3.32854360, 100: 3.328543604, 101: 3.3285436042}

        eps = np.finfo('f').eps
        for k, v in some_ds.iteritems():
            assert_true(abs(v - ds2[k]) < eps)

        # test I/O (through ascii files)
        surf.write(temp_fn, s, overwrite=True)
        s2 = surf.read(temp_fn)

        # test i/o and ensure that the loaded instance is trained
        if externals.exists('h5py'):
            h5save(temp_fn, s2)
            s2 = h5load(temp_fn)


        assert_array_almost_equal(s.vertices, s2.vertices, 4)
        assert_array_almost_equal(s.faces, s2.faces, 4)

        # test plane (new feature end of August 2012)
        s3 = surf.generate_plane((0, 0, 0), (2, 0, 0), (0, 1, 0), 10, 20)
        assert_equal(s3.nvertices, 200)
        assert_equal(s3.nfaces, 342)
        assert_array_almost_equal(s3.vertices[-1, :], np.array([18., 19, 0.]))
        assert_array_almost_equal(s3.faces[-1, :], np.array([199, 198, 179]))

        # test bar
        p, q = (0, 0, 0), (100, 0, 0)
        s4 = surf.generate_bar(p, q, 10, 12)
        assert_equal(s4.nvertices, 26)
        assert_equal(s4.nfaces, 48)
    def test_voxel_selection_alternative_calls(self):
        # Tests a multitude of different searchlight calls
        # that all should yield exactly the same results.
        #
        # Calls differ by whether the arguments are filenames
        # or data objects, whether values are specified explicityly
        # or set to the default implicitly (using None).
        # and by different calls to run the voxel selection.
        #
        # This method does not test for mask functionality.

        # define the volume
        vol_shape = (10, 10, 10, 3)
        vol_affine = np.identity(4)
        vol_affine[0, 0] = vol_affine[1, 1] = vol_affine[2, 2] = 5

        # four versions: array, nifti image, file name, fmri dataset
        volarr = np.ones(vol_shape)
        volimg = nb.Nifti1Image(volarr, vol_affine)
        # There is a detected problem with elderly NumPy's (e.g. 1.6.1
        # on precise on travis) leading to segfaults while operating
        # on memmapped volumes being forwarded to pprocess.
        # Thus just making it compressed volume for those cases
        suf = ".gz" if (externals.exists("pprocess") and externals.versions["numpy"] < "1.6.2") else ""
        fd, volfn = tempfile.mkstemp("vol.nii" + suf, "test")
        os.close(fd)
        volimg.to_filename(volfn)
        volds = fmri_dataset(volfn)

        fd, volfngz = tempfile.mkstemp("vol.nii.gz", "test")
        os.close(fd)
        volimg.to_filename(volfngz)
        voldsgz = fmri_dataset(volfngz)

        # make the surfaces
        sphere_density = 10

        # two versions: Surface and file name
        outer = surf.generate_sphere(sphere_density) * 25.0 + 15
        inner = surf.generate_sphere(sphere_density) * 20.0 + 15
        intermediate = inner * 0.5 + outer * 0.5
        nv = outer.nvertices

        fd, outerfn = tempfile.mkstemp("outer.asc", "test")
        os.close(fd)
        fd, innerfn = tempfile.mkstemp("inner.asc", "test")
        os.close(fd)
        fd, intermediatefn = tempfile.mkstemp("intermediate.asc", "test")
        os.close(fd)

        for s, fn in zip([outer, inner, intermediate], [outerfn, innerfn, intermediatefn]):
            surf.write(fn, s, overwrite=True)

        # searchlight radius (in mm)
        radius = 10.0

        # dataset used to run searchlight on
        ds = fmri_dataset(volfn)

        # simple voxel counter (run for each searchlight position)
        m = _Voxel_Count_Measure()

        # number of voxels expected in each searchlight
        r_expected = np.array(
            [
                [
                    18,
                    9,
                    10,
                    9,
                    9,
                    9,
                    9,
                    10,
                    9,
                    9,
                    9,
                    9,
                    11,
                    11,
                    11,
                    11,
                    10,
                    10,
                    10,
                    9,
                    10,
                    11,
                    9,
                    10,
                    10,
                    8,
                    7,
                    8,
                    8,
                    8,
                    9,
                    10,
                    12,
                    12,
                    11,
                    7,
                    7,
                    8,
                    5,
                    9,
                    11,
                    11,
                    12,
                    12,
                    9,
                    5,
                    8,
                    7,
                    7,
                    12,
                    12,
                    13,
                    12,
                    12,
                    7,
                    7,
                    8,
                    5,
                    9,
                    12,
                    12,
                    13,
                    11,
                    9,
                    5,
                    8,
                    7,
                    7,
                    11,
                    12,
                    12,
                    11,
                    12,
                    10,
                    10,
                    11,
                    9,
                    11,
                    12,
                    12,
                    12,
                    12,
                    16,
                    13,
                    16,
                    16,
                    16,
                    17,
                    15,
                    17,
                    17,
                    17,
                    16,
                    16,
                    16,
                    18,
                    16,
                    16,
                    16,
                    16,
                    18,
                    16,
                ]
            ]
        )

        params = dict(
            intermediate_=(intermediate, intermediatefn, None),
            center_nodes_=(None, range(nv)),
            volume_=(volimg, volfn, volds, volfngz, voldsgz),
            surf_src_=("filename", "surf"),
            volume_mask_=(None, True, 0, 2),
            call_method_=("qe", "rvs", "gam"),
        )

        combis = _cartprod(params)  # compute all possible combinations
        combistep = 17  # 173
        # some fine prime number to speed things up
        # if this value becomes too big then not all
        # cases are covered
        # the unit test tests itself whether all values
        # occur at least once

        tested_params = dict()

        def val2str(x):
            return "%r:%r" % (type(x), x)

        for i in xrange(0, len(combis), combistep):
            combi = combis[i]

            intermediate_ = combi["intermediate_"]
            center_nodes_ = combi["center_nodes_"]
            volume_ = combi["volume_"]
            surf_src_ = combi["surf_src_"]
            volume_mask_ = combi["volume_mask_"]
            call_method_ = combi["call_method_"]

            # keep track of which values were used -
            # so that this unit test tests itself

            for k in combi.keys():
                if not k in tested_params:
                    tested_params[k] = set()
                tested_params[k].add(val2str(combi[k]))

            if surf_src_ == "filename":
                s_i, s_m, s_o = inner, intermediate, outer
            elif surf_src_ == "surf":
                s_i, s_m, s_o = innerfn, intermediatefn, outerfn
            else:
                raise ValueError("this should not happen")

            if call_method_ == "qe":
                # use the fancy query engine wrapper
                qe = disc_surface_queryengine(
                    radius, volume_, s_i, s_o, s_m, source_surf_nodes=center_nodes_, volume_mask=volume_mask_
                )
                sl = Searchlight(m, queryengine=qe)
                r = sl(ds).samples

            elif call_method_ == "rvs":
                # use query-engine but build the
                # ingredients by hand
                vg = volgeom.from_any(volume_, volume_mask_)
                vs = volsurf.VolSurfMaximalMapping(vg, s_i, s_o)
                sel = surf_voxel_selection.voxel_selection(vs, radius, source_surf=s_m, source_surf_nodes=center_nodes_)
                qe = SurfaceVerticesQueryEngine(sel)
                sl = Searchlight(m, queryengine=qe)
                r = sl(ds).samples

            elif call_method_ == "gam":
                # build everything from the ground up
                vg = volgeom.from_any(volume_, volume_mask_)
                vs = volsurf.VolSurfMaximalMapping(vg, s_i, s_o)
                sel = surf_voxel_selection.voxel_selection(vs, radius, source_surf=s_m, source_surf_nodes=center_nodes_)
                mp = sel

                ks = sel.keys()
                nk = len(ks)
                r = np.zeros((1, nk))
                for i, k in enumerate(ks):
                    r[0, i] = len(mp[k])

            # check if result is as expected
            assert_array_equal(r_expected, r)

        # clean up
        all_fns = [volfn, volfngz, outerfn, innerfn, intermediatefn]
        map(os.remove, all_fns)

        for k, vs in params.iteritems():
            if not k in tested_params:
                raise ValueError("Missing key: %r" % k)
            for v in vs:
                vstr = val2str(v)
                if not vstr in tested_params[k]:
                    raise ValueError("Missing value %r for %s" % (tested_params[k], k))
Ejemplo n.º 4
0
    def test_afni_suma_spec(self, temp_dir):

        # XXX this function generates quite a few temporary files,
        #     which are removed at the end.
        #     the decorator @with_tempfile seems unsuitable as it only
        #     supports a single temporary file

        # make temporary directory
        os.mkdir(temp_dir)

        # generate surfaces
        inflated_surf = surf.generate_plane((0, 0, 0), (0, 1, 0), (0, 0, 1),
                                                    10, 10)
        white_surf = inflated_surf + 1.

        # helper function
        _tmp = lambda x:pathjoin(temp_dir, x)


        # filenames for surfaces and spec file
        inflated_fn = _tmp('_lh_inflated.asc')
        white_fn = _tmp('_lh_white.asc')
        spec_fn = _tmp('lh.spec')

        spec_dir = os.path.split(spec_fn)[0]

        # generate SUMA-like spec dictionary
        white = dict(SurfaceFormat='ASCII',
            EmbedDimension='3',
            SurfaceType='FreeSurfer',
            SurfaceName=white_fn,
            Anatomical='Y',
            LocalCurvatureParent='SAME',
            LocalDomainParent='SAME',
            SurfaceState='smoothwm')

        inflated = dict(SurfaceFormat='ASCII',
            EmbedDimension='3',
            SurfaceType='FreeSurfer',
            SurfaceName=inflated_fn,
            Anatomical='N',
            LocalCurvatureParent=white_fn,
            LocalDomainParent=white_fn,
            SurfaceState='inflated')

        # make SurfaceSpec object
        spec = afni_suma_spec.SurfaceSpec([white], directory=spec_dir)
        spec.add_surface(inflated)

        # test __str__ and __repr__
        assert_true('SurfaceSpec instance with 2 surfaces'
                        ', 2 states ' in '%s' % spec)
        assert_true(('%r' % spec).startswith('SurfaceSpec'))

        # test finding surfaces
        inflated_ = spec.find_surface_from_state('inflated')
        assert_equal([(1, inflated)], inflated_)

        empty = spec.find_surface_from_state('unknown')
        assert_equal(empty, [])

        # test .same_states
        minimal = afni_suma_spec.SurfaceSpec([dict(SurfaceState=s)
                                            for s in ('smoothwm', 'inflated')])
        assert_true(spec.same_states(minimal))
        assert_false(spec.same_states(afni_suma_spec.SurfaceSpec(dict())))

        # test 'smart' surface file matching
        assert_equal(spec.get_surface_file('smo'), white_fn)
        assert_equal(spec.get_surface_file('inflated'), inflated_fn)
        assert_equal(spec.get_surface_file('this should be None'), None)

        # test i/o
        spec.write(spec_fn)
        spec_ = afni_suma_spec.from_any(spec_fn)

        # prepare for another (right-hemisphere) spec file
        lh_spec = spec
        rh_spec_fn = spec_fn.replace('lh', 'rh')

        rh_inflated_fn = _tmp(os.path.split(inflated_fn)[1].replace('_lh',
                                                                    '_rh'))
        rh_white_fn = _tmp(os.path.split(white_fn)[1].replace('_lh',
                                                              '_rh'))
        rh_spec_fn = _tmp('rh.spec')

        rh_white = dict(SurfaceFormat='ASCII',
            EmbedDimension='3',
            SurfaceType='FreeSurfer',
            SurfaceName=rh_white_fn,
            Anatomical='Y',
            LocalCurvatureParent='SAME',
            LocalDomainParent='SAME',
            SurfaceState='smoothwm')

        rh_inflated = dict(SurfaceFormat='ASCII',
            EmbedDimension='3',
            SurfaceType='FreeSurfer',
            SurfaceName=rh_inflated_fn,
            Anatomical='N',
            LocalCurvatureParent=rh_white_fn,
            LocalDomainParent=rh_white_fn,
            SurfaceState='inflated')

        rh_spec = afni_suma_spec.SurfaceSpec([rh_white], directory=spec_dir)
        rh_spec.add_surface(rh_inflated)

        # write files
        all_temp_fns = [spec_fn, rh_spec_fn]
        for fn, s in [(rh_inflated_fn, inflated_surf),
                      (rh_white_fn, white_surf),
                      (inflated_fn, inflated_surf),
                      (white_fn, white_surf)]:
            surf.write(fn, s)
            all_temp_fns.append(fn)

        # test adding views
        added_specs = afni_suma_spec.hemi_pairs_add_views((lh_spec, rh_spec),
                                                          'inflated', '.asc')

        for hemi, added_spec in zip(('l', 'r'), added_specs):
            states = ['smoothwm', 'inflated'] + ['CoM%sinflated' % i
                                                    for i in 'msiap']
            assert_equal(states, [s['SurfaceState']
                                  for s in added_specs[0].surfaces])
            all_temp_fns.extend([s['SurfaceName']
                                 for s in added_spec.surfaces])

        # test combining specs (bh=both hemispheres)
        bh_spec = afni_suma_spec.combine_left_right(added_specs)

        # test merging specs (mh=merged hemispheres)
        mh_spec, mh_surfs = afni_suma_spec.merge_left_right(bh_spec)

        assert_equal([s['SurfaceState'] for s in mh_spec.surfaces],
                    ['smoothwm'] + ['CoM%sinflated' % i for i in 'msiap'])
Ejemplo n.º 5
0
    def test_afni_suma_spec(self, temp_dir):

        # XXX this function generates quite a few temporary files,
        #     which are removed at the end.
        #     the decorator @with_tempfile seems unsuitable as it only
        #     supports a single temporary file

        # make temporary directory
        os.mkdir(temp_dir)

        # generate surfaces
        inflated_surf = surf.generate_plane((0, 0, 0), (0, 1, 0), (0, 0, 1),
                                            10, 10)
        white_surf = inflated_surf + 1.

        # helper function
        _tmp = lambda x: os.path.join(temp_dir, x)

        # filenames for surfaces and spec file
        inflated_fn = _tmp('_lh_inflated.asc')
        white_fn = _tmp('_lh_white.asc')
        spec_fn = _tmp('lh.spec')

        spec_dir = os.path.split(spec_fn)[0]

        # generate SUMA-like spec dictionary
        white = dict(SurfaceFormat='ASCII',
                     EmbedDimension='3',
                     SurfaceType='FreeSurfer',
                     SurfaceName=white_fn,
                     Anatomical='Y',
                     LocalCurvatureParent='SAME',
                     LocalDomainParent='SAME',
                     SurfaceState='smoothwm')

        inflated = dict(SurfaceFormat='ASCII',
                        EmbedDimension='3',
                        SurfaceType='FreeSurfer',
                        SurfaceName=inflated_fn,
                        Anatomical='N',
                        LocalCurvatureParent=white_fn,
                        LocalDomainParent=white_fn,
                        SurfaceState='inflated')

        # make SurfaceSpec object
        spec = afni_suma_spec.SurfaceSpec([white], directory=spec_dir)
        spec.add_surface(inflated)

        # test __str__ and __repr__
        assert_true('SurfaceSpec instance with 2 surfaces'
                    ', 2 states ' in '%s' % spec)
        assert_true(('%r' % spec).startswith('SurfaceSpec'))

        # test finding surfaces
        inflated_ = spec.find_surface_from_state('inflated')
        assert_equal([(1, inflated)], inflated_)

        empty = spec.find_surface_from_state('unknown')
        assert_equal(empty, [])

        # test .same_states
        minimal = afni_suma_spec.SurfaceSpec(
            [dict(SurfaceState=s) for s in ('smoothwm', 'inflated')])
        assert_true(spec.same_states(minimal))
        assert_false(spec.same_states(afni_suma_spec.SurfaceSpec(dict())))

        # test 'smart' surface file matching
        assert_equal(spec.get_surface_file('smo'), white_fn)
        assert_equal(spec.get_surface_file('inflated'), inflated_fn)
        assert_equal(spec.get_surface_file('this should be None'), None)

        # test i/o
        spec.write(spec_fn)
        spec_ = afni_suma_spec.from_any(spec_fn)

        # prepare for another (right-hemisphere) spec file
        lh_spec = spec
        rh_spec_fn = spec_fn.replace('lh', 'rh')

        rh_inflated_fn = _tmp(
            os.path.split(inflated_fn)[1].replace('_lh', '_rh'))
        rh_white_fn = _tmp(os.path.split(white_fn)[1].replace('_lh', '_rh'))
        rh_spec_fn = _tmp('rh.spec')

        rh_white = dict(SurfaceFormat='ASCII',
                        EmbedDimension='3',
                        SurfaceType='FreeSurfer',
                        SurfaceName=rh_white_fn,
                        Anatomical='Y',
                        LocalCurvatureParent='SAME',
                        LocalDomainParent='SAME',
                        SurfaceState='smoothwm')

        rh_inflated = dict(SurfaceFormat='ASCII',
                           EmbedDimension='3',
                           SurfaceType='FreeSurfer',
                           SurfaceName=rh_inflated_fn,
                           Anatomical='N',
                           LocalCurvatureParent=rh_white_fn,
                           LocalDomainParent=rh_white_fn,
                           SurfaceState='inflated')

        rh_spec = afni_suma_spec.SurfaceSpec([rh_white], directory=spec_dir)
        rh_spec.add_surface(rh_inflated)

        # write files
        all_temp_fns = [spec_fn, rh_spec_fn]
        for fn, s in [(rh_inflated_fn, inflated_surf),
                      (rh_white_fn, white_surf), (inflated_fn, inflated_surf),
                      (white_fn, white_surf)]:
            surf.write(fn, s)
            all_temp_fns.append(fn)

        # test adding views
        added_specs = afni_suma_spec.hemi_pairs_add_views((lh_spec, rh_spec),
                                                          'inflated', '.asc')

        for hemi, added_spec in zip(('l', 'r'), added_specs):
            states = ['smoothwm', 'inflated'
                      ] + ['CoM%sinflated' % i for i in 'msiap']
            assert_equal(states,
                         [s['SurfaceState'] for s in added_specs[0].surfaces])
            all_temp_fns.extend(
                [s['SurfaceName'] for s in added_spec.surfaces])

        # test combining specs (bh=both hemispheres)
        bh_spec = afni_suma_spec.combine_left_right(added_specs)

        # test merging specs (mh=merged hemispheres)
        mh_spec, mh_surfs = afni_suma_spec.merge_left_right(bh_spec)

        assert_equal([s['SurfaceState'] for s in mh_spec.surfaces],
                     ['smoothwm'] + ['CoM%sinflated' % i for i in 'msiap'])
Ejemplo n.º 6
0
def run_makespec_bothhemis(config, env):
    refdir = config['refdir']
    overwrite = config['overwrite']
    icolds, hemis = _get_hemis_icolds(config)

    ext = format2extension(config)

    if hemis != ['l', 'r']:
        raise ValueError("Cannot run without left and right hemisphere")

    for icold in icolds:
        specs = []
        for hemi in hemis:
            #surfprefix = '%s%sh' % (config['mi_icopat'] % icold, hemi)
            specfn = afni_suma_spec.canonical_filename(icold, hemi,
                                                       config['alsuffix'])
            specpathfn = os.path.join(refdir, specfn)
            s = afni_suma_spec.read(specpathfn)

            specs.append(afni_suma_spec.read(specpathfn))

        add_states = ['inflated', 'full.patch.flat', 'sphere.reg']
        add_states_required = [True, False, True]  # flat surface is optional
        for add_state, is_req in zip(add_states, add_states_required):
            has_state = all([
                len(spec.find_surface_from_state(add_state)) == 1
                for spec in specs
            ])

            if not has_state:
                if is_req:
                    error('cannot find state %s' % add_state)
                else:
                    # skip this state
                    print "Optional state %s not found - skipping" % add_state
                    continue

            specs = afni_suma_spec.hemi_pairs_add_views(specs,
                                                        add_state,
                                                        ext,
                                                        refdir,
                                                        overwrite=overwrite)

        spec_both = afni_suma_spec.combine_left_right(specs)

        # generate spec files for both hemispheres
        hemiboth = 'b'
        specfn = afni_suma_spec.canonical_filename(icold, hemiboth,
                                                   config['alsuffix'])
        specpathfn = os.path.join(refdir, specfn)
        spec_both.write(specpathfn, overwrite=overwrite)

        # merge left and right into one surface
        # and generate the spec files as well
        hemimerged = 'm'
        specfn = afni_suma_spec.canonical_filename(icold, hemimerged,
                                                   config['alsuffix'])
        specpathfn = os.path.join(refdir, specfn)

        if config['overwrite'] or not os.path.exists(specpathfn):
            spec_merged, surfs_to_join = afni_suma_spec.merge_left_right(
                spec_both)
            spec_merged.write(specpathfn, overwrite=overwrite)

            full_path = lambda x: os.path.join(refdir, x)
            for fn_out, fns_in in surfs_to_join.iteritems():
                surfs_in = [surf.read(full_path(fn)) for fn in fns_in]

                if all(['full.patch.flat' in fn for fn in fns_in]):
                    # left hemi of flat; rotate 180 degrees, reposition again
                    surfs_in[0] = surfs_in[0] * [-1, -1, 1]
                    surfs_in = surf.reposition_hemisphere_pairs(
                        surfs_in[0], surfs_in[1], 'm')

                surf_merged = surf.merge(*surfs_in)

                if config['overwrite'] or not os.path.exists(
                        full_path(fn_out)):
                    surf.write(full_path(fn_out), surf_merged)
                    print "Merged surfaces written to %s" % fn_out
Ejemplo n.º 7
0
    def test_voxel_selection_alternative_calls(self):
        # Tests a multitude of different searchlight calls
        # that all should yield exactly the same results.
        #
        # Calls differ by whether the arguments are filenames
        # or data objects, whether values are specified explicityly
        # or set to the default implicitly (using None).
        # and by different calls to run the voxel selection.
        #
        # This method does not test for mask functionality.

        # define the volume
        vol_shape = (10, 10, 10, 3)
        vol_affine = np.identity(4)
        vol_affine[0, 0] = vol_affine[1, 1] = vol_affine[2, 2] = 5

        # four versions: array, nifti image, file name, fmri dataset
        volarr = np.ones(vol_shape)
        volimg = nb.Nifti1Image(volarr, vol_affine)
        # There is a detected problem with elderly NumPy's (e.g. 1.6.1
        # on precise on travis) leading to segfaults while operating
        # on memmapped volumes being forwarded to pprocess.
        # Thus just making it compressed volume for those cases
        suf = '.gz' \
            if externals.exists('pprocess') and externals.versions['numpy'] < '1.6.2' \
            else ''
        fd, volfn = tempfile.mkstemp('vol.nii' + suf, 'test')
        os.close(fd)
        volimg.to_filename(volfn)
        volds = fmri_dataset(volfn)

        fd, volfngz = tempfile.mkstemp('vol.nii.gz', 'test')
        os.close(fd)
        volimg.to_filename(volfngz)
        voldsgz = fmri_dataset(volfngz)

        # make the surfaces
        sphere_density = 10

        # two versions: Surface and file name
        outer = surf.generate_sphere(sphere_density) * 25. + 15
        inner = surf.generate_sphere(sphere_density) * 20. + 15
        intermediate = inner * .5 + outer * .5
        nv = outer.nvertices

        fd, outerfn = tempfile.mkstemp('outer.asc', 'test')
        os.close(fd)
        fd, innerfn = tempfile.mkstemp('inner.asc', 'test')
        os.close(fd)
        fd, intermediatefn = tempfile.mkstemp('intermediate.asc', 'test')
        os.close(fd)

        for s, fn in zip([outer, inner, intermediate],
                         [outerfn, innerfn, intermediatefn]):
            surf.write(fn, s, overwrite=True)

        # searchlight radius (in mm)
        radius = 10.

        # dataset used to run searchlight on
        ds = fmri_dataset(volfn)

        # simple voxel counter (run for each searchlight position)
        m = _Voxel_Count_Measure()

        # number of voxels expected in each searchlight
        r_expected = np.array([[
            18, 9, 10, 9, 9, 9, 9, 10, 9, 9, 9, 9, 11, 11, 11, 11, 10, 10, 10,
            9, 10, 11, 9, 10, 10, 8, 7, 8, 8, 8, 9, 10, 12, 12, 11, 7, 7, 8, 5,
            9, 11, 11, 12, 12, 9, 5, 8, 7, 7, 12, 12, 13, 12, 12, 7, 7, 8, 5,
            9, 12, 12, 13, 11, 9, 5, 8, 7, 7, 11, 12, 12, 11, 12, 10, 10, 11,
            9, 11, 12, 12, 12, 12, 16, 13, 16, 16, 16, 17, 15, 17, 17, 17, 16,
            16, 16, 18, 16, 16, 16, 16, 18, 16
        ]])

        params = dict(intermediate_=(intermediate, intermediatefn, None),
                      center_nodes_=(None, range(nv)),
                      volume_=(volimg, volfn, volds, volfngz, voldsgz),
                      surf_src_=('filename', 'surf'),
                      volume_mask_=(None, True, 0, 2),
                      call_method_=("qe", "rvs", "gam"))

        combis = _cartprod(params)  # compute all possible combinations
        combistep = 17  #173
        # some fine prime number to speed things up
        # if this value becomes too big then not all
        # cases are covered
        # the unit test tests itself whether all values
        # occur at least once

        tested_params = dict()

        def val2str(x):
            return '%r:%r' % (type(x), x)

        for i in xrange(0, len(combis), combistep):
            combi = combis[i]

            intermediate_ = combi['intermediate_']
            center_nodes_ = combi['center_nodes_']
            volume_ = combi['volume_']
            surf_src_ = combi['surf_src_']
            volume_mask_ = combi['volume_mask_']
            call_method_ = combi['call_method_']

            # keep track of which values were used -
            # so that this unit test tests itself

            for k in combi.keys():
                if not k in tested_params:
                    tested_params[k] = set()
                tested_params[k].add(val2str(combi[k]))

            if surf_src_ == 'filename':
                s_i, s_m, s_o = inner, intermediate, outer
            elif surf_src_ == 'surf':
                s_i, s_m, s_o = innerfn, intermediatefn, outerfn
            else:
                raise ValueError('this should not happen')

            if call_method_ == "qe":
                # use the fancy query engine wrapper
                qe = disc_surface_queryengine(radius,
                                              volume_,
                                              s_i,
                                              s_o,
                                              s_m,
                                              source_surf_nodes=center_nodes_,
                                              volume_mask=volume_mask_)
                sl = Searchlight(m, queryengine=qe)
                r = sl(ds).samples

            elif call_method_ == 'rvs':
                # use query-engine but build the
                # ingredients by hand
                vg = volgeom.from_any(volume_, volume_mask_)
                vs = volsurf.VolSurfMaximalMapping(vg, s_i, s_o)
                sel = surf_voxel_selection.voxel_selection(
                    vs,
                    radius,
                    source_surf=s_m,
                    source_surf_nodes=center_nodes_)
                qe = SurfaceVerticesQueryEngine(sel)
                sl = Searchlight(m, queryengine=qe)
                r = sl(ds).samples

            elif call_method_ == 'gam':
                # build everything from the ground up
                vg = volgeom.from_any(volume_, volume_mask_)
                vs = volsurf.VolSurfMaximalMapping(vg, s_i, s_o)
                sel = surf_voxel_selection.voxel_selection(
                    vs,
                    radius,
                    source_surf=s_m,
                    source_surf_nodes=center_nodes_)
                mp = sel

                ks = sel.keys()
                nk = len(ks)
                r = np.zeros((1, nk))
                for i, k in enumerate(ks):
                    r[0, i] = len(mp[k])

            # check if result is as expected
            assert_array_equal(r_expected, r)

        # clean up
        all_fns = [volfn, volfngz, outerfn, innerfn, intermediatefn]
        map(os.remove, all_fns)

        for k, vs in params.iteritems():
            if not k in tested_params:
                raise ValueError("Missing key: %r" % k)
            for v in vs:
                vstr = val2str(v)
                if not vstr in tested_params[k]:
                    raise ValueError("Missing value %r for %s" %
                                     (tested_params[k], k))
Ejemplo n.º 8
0
    def test_surf(self, temp_fn):
        """Some simple testing with surfaces
        """

        s = surf.generate_sphere(10)

        assert_true(s.nvertices == 102)
        assert_true(s.nfaces == 200)

        v = s.vertices
        f = s.faces

        assert_true(v.shape == (102, 3))
        assert_true(f.shape == (200, 3))

        # another surface
        t = s * 10 + 2
        assert_true(t.same_topology(s))
        assert_array_equal(f, t.faces)

        assert_array_equal(v * 10 + 2, t.vertices)

        # allow updating, but should not affect original array
        # CHECKME: maybe we want to throw an exception instead
        assert_true((v * 10 + 2 == t.vertices).all().all())
        assert_true((s.vertices * 10 + 2 == t.vertices).all().all())

        # a few checks on vertices and nodes
        v_check = {
            40: (0.86511144, -0.28109175, -0.41541501),
            10: (0.08706015, -0.26794358, -0.95949297)
        }
        f_check = {10: (7, 8, 1), 40: (30, 31, 21)}

        vf_checks = [(v_check, lambda x: x.vertices),
                     (f_check, lambda x: x.faces)]

        eps = .0001
        for cmap, f in vf_checks:
            for k, v in cmap.iteritems():
                surfval = f(s)[k, :]
                assert_true((abs(surfval - v) < eps).all())

        # make sure same topology fails with different topology
        u = surf.generate_cube()
        assert_false(u.same_topology(s))

        # check that neighbours are computed correctly
        # even if we nuke the topology afterwards
        for _ in [0, 1]:
            nbrs = s.neighbors
            n_check = [(0, 96, 0.284629), (40, 39, 0.56218349),
                       (100, 99, 0.1741202)]
            for i, j, k in n_check:
                assert_true(abs(nbrs[i][j] - k) < eps)

        def assign_zero(x):
            x.faces[:, :] = 0
            return None

        assert_raises((ValueError, RuntimeError), assign_zero, s)

        # see if mapping to high res works
        h = surf.generate_sphere(40)

        low2high = s.map_to_high_resolution_surf(h, .1)
        partmap = {7: 141, 8: 144, 9: 148, 10: 153, 11: 157, 12: 281}
        for k, v in partmap.iteritems():
            assert_true(low2high[k] == v)

        # ensure that slow implementation gives same results as fast one
        low2high_slow = s.map_to_high_resolution_surf(h, .1)
        for k, v in low2high.iteritems():
            assert_true(low2high_slow[k] == v)

        #  should fail if epsilon is too small
        assert_raises(ValueError,
                      lambda x: x.map_to_high_resolution_surf(h, .01), s)

        n2f = s.node2faces
        for i in xrange(s.nvertices):
            nf = [10] if i < 2 else [5, 6]  # number of faces expected

            assert_true(len(n2f[i]) in nf)

        # test dijkstra distances
        ds2 = s.dijkstra_distance(2)
        some_ds = {
            0: 3.613173280799,
            1: 0.2846296765,
            2: 0.,
            52: 1.87458018,
            53: 2.0487004817,
            54: 2.222820777,
            99: 3.32854360,
            100: 3.328543604,
            101: 3.3285436042
        }

        eps = np.finfo('f').eps
        for k, v in some_ds.iteritems():
            assert_true(abs(v - ds2[k]) < eps)

        # test I/O (through ascii files)
        surf.write(temp_fn, s, overwrite=True)
        s2 = surf.read(temp_fn)

        # test i/o and ensure that the loaded instance is trained
        if externals.exists('h5py'):
            h5save(temp_fn, s2)
            s2 = h5load(temp_fn)

        assert_array_almost_equal(s.vertices, s2.vertices, 4)
        assert_array_almost_equal(s.faces, s2.faces, 4)

        # test plane (new feature end of August 2012)
        s3 = surf.generate_plane((0, 0, 0), (2, 0, 0), (0, 1, 0), 10, 20)
        assert_equal(s3.nvertices, 200)
        assert_equal(s3.nfaces, 342)
        assert_array_almost_equal(s3.vertices[-1, :], np.array([18., 19, 0.]))
        assert_array_almost_equal(s3.faces[-1, :], np.array([199, 198, 179]))

        # test bar
        p, q = (0, 0, 0), (100, 0, 0)
        s4 = surf.generate_bar(p, q, 10, 12)
        assert_equal(s4.nvertices, 26)
        assert_equal(s4.nfaces, 48)
Ejemplo n.º 9
0
def run_makespec_bothhemis(config, env):
    refdir = config['refdir']
    overwrite = config['overwrite']
    icolds, hemis = _get_hemis_icolds(config)

    ext = format2extension(config)

    if hemis != ['l', 'r']:
        raise ValueError("Cannot run without left and right hemisphere")

    for icold in icolds:
        specs = []
        for hemi in hemis:
            #surfprefix = '%s%sh' % (config['mi_icopat'] % icold, hemi)
            specfn = afni_suma_spec.canonical_filename(icold, hemi,
                                                       config['alsuffix'])
            specpathfn = pathjoin(refdir, specfn)
            s = afni_suma_spec.read(specpathfn)

            specs.append(afni_suma_spec.read(specpathfn))

        add_states = ['inflated', 'full.patch.flat', 'sphere.reg']
        add_states_required = [True, False, True] # flat surface is optional
        for add_state, is_req in zip(add_states, add_states_required):
            has_state = all([len(spec.find_surface_from_state(add_state)) == 1
                                    for spec in specs])

            if not has_state:
                if is_req:
                    error('cannot find state %s' % add_state)
                else:
                    # skip this state
                    print "Optional state %s not found - skipping" % add_state
                    continue

            specs = afni_suma_spec.hemi_pairs_add_views(specs,
                            add_state, ext, refdir, overwrite=overwrite)


        spec_both = afni_suma_spec.combine_left_right(specs)


        # generate spec files for both hemispheres
        hemiboth = 'b'
        specfn = afni_suma_spec.canonical_filename(icold, hemiboth, config['alsuffix'])
        specpathfn = pathjoin(refdir, specfn)
        spec_both.write(specpathfn, overwrite=overwrite)

        # merge left and right into one surface
        # and generate the spec files as well
        hemimerged = 'm'
        specfn = afni_suma_spec.canonical_filename(icold, hemimerged, config['alsuffix'])
        specpathfn = pathjoin(refdir, specfn)

        if config['overwrite'] or not os.path.exists(specpathfn):
            spec_merged, surfs_to_join = afni_suma_spec.merge_left_right(spec_both)
            spec_merged.write(specpathfn, overwrite=overwrite)

            full_path = lambda x:pathjoin(refdir, x)
            for fn_out, fns_in in surfs_to_join.iteritems():
                surfs_in = [surf.read(full_path(fn)) for fn in fns_in]

                if all(['full.patch.flat' in fn for fn in fns_in]):
                    # left hemi of flat; rotate 180 degrees, reposition again
                    surfs_in[0] = surfs_in[0] * [-1, -1, 1]
                    surfs_in = surf.reposition_hemisphere_pairs(surfs_in[0], surfs_in[1], 'm')

                surf_merged = surf.merge(*surfs_in)

                if config['overwrite'] or not os.path.exists(full_path(fn_out)):
                    surf.write(full_path(fn_out), surf_merged)
                    print "Merged surfaces written to %s" % fn_out
Ejemplo n.º 10
0
def hemi_pairs_add_views(spec_both, state, ext, directory=None, overwrite=False):
    '''adds views for medial, superior, inferior, anterior, posterior viewing
    of two surfaces together. Also generates these surfaces'''

    spec_left, spec_right = spec_both[0], spec_both[1]

    if directory is None:
        directory = os.path.curdir

    if not spec_left.same_states(spec_right):
        raise ValueError('Incompatible states for left and right')

    #views = collections.OrderedDict(m='medial', s='superior', i='inferior', a='anterior', p='posterior')
    # for compatibility use a normal dict

    if state == 'inflated':
        views = dict(m='medial', s='superior', i='inferior', a='anterior', p='posterior')
        viewkeys = ['m', 's', 'i', 'a', 'p']
    else:
        views = dict(m='medial')
        viewkeys = 'm'

    spec_both = [spec_left, spec_right]
    spec_both_new = map(copy.deepcopy, spec_both)

    for view in viewkeys:
        longname = views[view]
        oldfns = []
        newfns = []
        for i, spec in enumerate(spec_both):

            idxdef = spec.find_surface_from_state(state)
            if len(idxdef) != 1:
                raise ValueError('Not unique surface with state %s' % state)
            surfidx, surfdef = idxdef[0]

            # take whichever is there (in order of preference)
            # shame that python has no builtin foldr
            surfnamelabels = ['SurfaceName', 'FreeSurferSurface']
            for surfnamelabel in surfnamelabels:
                surfname = surfdef.get(surfnamelabel)
                if not surfname is None:
                    break
            #surfname = utils.foldr(surfdef.get, None, surfnamelabels)

            fn = os.path.join(directory, surfname)
            if not os.path.exists(fn):
                raise ValueError("File not found: %s" % fn)

            if not surfname.endswith(ext):
                raise ValueError('Expected extension %s for %s' % (ext, fn))
            oldfns.append(fn) # store old name

            shortfn = surfname[:-(len(ext))]
            newsurfname = '%s%s%s%s' % (shortfn, _COMPREFIX, longname, ext)
            newfn = os.path.join(directory, newsurfname)

            newsurfdef = copy.deepcopy(surfdef)

            # ensure no naming cnoflicts
            for surfnamelabel in surfnamelabels:
                if surfnamelabel in newsurfdef:
                    newsurfdef.pop(surfnamelabel)
            newsurfdef['SurfaceName'] = newsurfname
            newsurfdef['SurfaceState'] = '%s%s%s' % (_COMPREFIX, view, state)
            spec_both_new[i].add_surface(newsurfdef)
            newfns.append(newfn)

        if all(map(os.path.exists, newfns)) and not overwrite:
            print "Output already exist for %s" % longname
        else:
            surf_left, surf_right = map(surf.read, oldfns)
            surf_both_moved = surf.reposition_hemisphere_pairs(surf_left,
                                                               surf_right,
                                                               view)

            for fn, surf_ in zip(newfns, surf_both_moved):
                surf.write(fn, surf_, overwrite)
                print "Written %s" % fn

    return tuple(spec_both_new)
Ejemplo n.º 11
0
def run_alignment(config, env):
    '''Aligns anat (which is assumed to be aligned with EPI data) to FreeSurfer SurfVol

    This function strips the anatomicals (by default), then uses align_epi_anat.py
    to estimate the alignment, then applies this transformation to the non-skull-stripped
    SurfVol and also to the surfaces. Some alignment headers will be nuked'''
    overwrite = config['overwrite']
    alignsuffix = config['al2expsuffix']
    refdir = config['refdir']

    fullext = config['outvol_fullext']
    ext = config['outvol_ext']

    if config['sid'] is None:
        raise ValueError('Need sid')

    cmds = []
    if not os.path.exists(config['refdir']):
        cmds.append('mkdir %(refdir)s' % config)

    # two volumes may have to be stripped: the inpput anatomical, and the surfvol.
    # put them in a list here and process them similarly
    surfvol = '%(refdir)s/%(sid)s_SurfVol%(outvol_fullext)s' % config
    surfvol_ss = '%(refdir)s/%(sid)s_SurfVol%(sssuffix)s%(outvol_fullext)s' % config

    e_p, e_n, _, _ = utils.afni_fileparts(config['expvol'])
    if config['expvol_ss']:
        e_n = '%s%s' % (e_n, config['sssuffix'])
    expvol = '%s/%s%s' % (refdir, e_n, fullext)

    volsin = [surfvol_ss, expvol]
    for volin in volsin:
        if not os.path.exists(volin):
            raise ValueError('File %s does not exist' % volin)

    a_n = utils.afni_fileparts(volsin[0])[1] # surfvol input root name
    ssalprefix = '%s%s' % (a_n, alignsuffix)

    unity = "1 0 0 0 0 1 0 0 0 0 1 0" # we all like unity, don't we?

    fullmatrixfn = '%s_mat.aff12.1D' % ssalprefix
    aloutfns = ['%s%s' % (ssalprefix, fullext), fullmatrixfn] # expected output files if alignment worked
    if config['overwrite'] or not all([os.path.exists('%s/%s' % (refdir, f)) for f in aloutfns]):
        alignedfn = '%s/%s%s' % (refdir, ssalprefix, fullext)

        if config['identity']:
            fullmatrix_content = '"MATRIX(%s)"' % unity.replace(" ", ",")

            cmd = 'cd "%s"; cat_matvec %s > %s; 3dcopy -overwrite %s%s %s%s%s' % (refdir, fullmatrix_content, fullmatrixfn, a_n, ext, a_n, alignsuffix, ext)
        else:
            # use different inputs depending on whether expvol is EPI or ANAT
            twovolpat = ('-anat %s -epi %s -anat2epi -epi_base 0 -anat_has_skull no -epi_strip None' if config['isepi']
                       else '-dset1 %s -dset2 %s -dset1to2 -dset1_strip None -dset2_strip None')
            # use this pattern to generate a suffix
            twovolsuffix = twovolpat % (volsin[0], volsin[1])

            aea_opts = config['aea_opts']
            if config['template']:
                aea_opts += " -Allineate_opts '-maxrot 10 -maxshf 10 -maxscl 1.5'"
            # align_epi_anat.py
            cmd = 'cd "%s"; align_epi_anat.py -overwrite -suffix %s %s %s' % (refdir, alignsuffix, twovolsuffix, aea_opts)

        cmds.append(cmd)

        cmds.append(_set_vol_space_cmd(alignedfn, config))

        utils.run_cmds(cmds, env)

    else:
        print "Alignment already done - skipping"

        # run these commands first, then check if everything worked properly


    cmds = []

    # see if the expected transformation file was found
    if not config['identity'] and not os.path.exists('%s/%s' % (refdir, fullmatrixfn)):
        raise Exception("Could not find %s in %s" % (fullmatrixfn, refdir))

    # now make a 3x4 matrix
    matrixfn = '%s%s.A2E.1D' % (a_n, alignsuffix)
    if overwrite or not os.path.exists('%s/%s' % (refdir, matrixfn)):
        cmds.append('cd "%s"; cat_matvec %s > %s || exit 1' % (refdir, fullmatrixfn, matrixfn))


    # make an aligned, non-skullstripped version of SurfVol in refdir
    alprefix = '%s_SurfVol%s' % (config['sid'], alignsuffix)
    svalignedfn = '%s/%s%s' % (refdir, alprefix, fullext)

    newgrid = 1 # size of anatomical grid in mm. We'll have to resample, otherwise 3dWarp does
              # not respect the corners of the volume (as of April 2012)

    if overwrite or not os.path.exists(svalignedfn):
        #if not config['fs_sid']:
        #    raise ValueError("Don't have a freesurfer subject id - cannot continue")

        #surfvolfn = '%s/%s_SurfVol+orig' % (config['sumadir'], config['fs_sid'])
        surfvolfn = '%s/T1.nii' % config['sumadir']
        cmds.append('cd "%s";3dWarp -overwrite -newgrid %f -matvec_out2in `cat_matvec -MATRIX %s` -prefix ./%s %s' %
                    (refdir, newgrid, matrixfn, alprefix, surfvolfn))
        cmds.append(_set_vol_space_cmd('%s/%s+orig' % (refdir, alprefix), config))

    else:
        print '%s already exists - skipping Warp' % svalignedfn

    utils.run_cmds(cmds, env)
    cmds = []

    # nuke afni headers
    headernukefns = ['%s%s' % (f, fullext) for f in [ssalprefix, alprefix]]
    headernukefields = ['ALLINEATE_MATVEC_B2S_000000',
                      'ALLINEATE_MATVEC_S2B_000000',
                      'WARPDRIVE_MATVEC_FOR_000000',
                      'WARPDRIVE_MATVEC_INV_000000']

    for fn in headernukefns:
        for field in headernukefields:
            # nuke transformation - otherwise AFNI does this unwanted transformation for us
            fullfn = '%s/%s' % (refdir, fn)

            if not (os.path.exists(fullfn) or config['identity']):
                raise ValueError("File %r does not exist" % fullfn)

            refitcmd = "3drefit -atrfloat %s '%s' %s" % (field, unity, fn)

            # only refit if not already in AFNI history (which is stored in HEADfile)
            cmd = 'cd "%s"; m=`grep "%s" %s | wc -w`; if [ $m -eq 0 ]; then %s; else echo "File %s seems already 3drefitted"; fi' % (refdir, refitcmd, fn, refitcmd, fn)
            cmds.append(cmd)
    utils.run_cmds('; '.join(cmds), env)
    cmds = []

    # run AddEdge so that volumes can be inspected visually for alignment
    if config['AddEdge']:
        use_ss = config['expvol_ss']

        # ae_{e,s}_n are AddEdge names for expvol and surfvol
        ae_e_n = utils.afni_fileparts(config['expvol'])[1]
        if use_ss:
            ae_e_n += config['sssuffix']
        ae_s_n = ssalprefix #if use_ss else alprefix

        # *_ne have the output extension as well
        ae_e_ne = ae_e_n + ext
        ae_s_ne = ae_s_n + ext

        addedge_fns = ['%s/_ae.ExamineList.log' % refdir]

        exts = ['HEAD', 'BRIK']
        orig_ext = '+orig'
        addedge_rootfns = ['%s_%s%%s' % (ae_e_n, postfix)
                            for postfix in ['e3', 'ec', ae_s_n + '_ec']]
        addedge_rootfns.extend(['%s_%s%%s' % (ae_s_n, postfix)
                            for postfix in ['e3', 'ec']])

        addedge_fns_pat = ['%s.%s' % (fn, e) for fn in addedge_rootfns for e in exts]

        addegde_pathfns_orig = map(lambda x:pathjoin(refdir, x % '+orig'), addedge_fns_pat) + addedge_fns
        addegde_pathfns_ext = map(lambda x:pathjoin(refdir, x % ext), addedge_fns_pat)
        addegde_exists = map(os.path.exists, addegde_pathfns_ext)
        if overwrite or not all(addegde_exists):
            ae_ns = (ae_e_n, ae_s_n)

            cmds.extend(map(lambda fn : 'if [ -e "%s" ]; then rm "%s"; fi' % (fn, fn), addegde_pathfns_orig + addegde_pathfns_ext))
            cmds.append(';'.join(['cd %s' % refdir] +
                                 [_convert_vol_space_to_orig_cmd('%s/%s%s' % (refdir, n, ext))
                                            for n in ae_ns] +
                                 ['\@AddEdge %s+orig %s+orig' % ae_ns]))

            set_space_fns = addegde_pathfns_orig + ['%s/%s%s.%s' % (refdir, fn, orig_ext, exts[0]) for fn in ae_ns]

            for fn in set_space_fns: #['%s/%s' % (refdir, fn % orig_ext) for fn in addedge_fns_pat]:
                if fn.endswith('.log'):
                    continue
                cmds.append('if [ -e %s ]; then %s; fi' % (fn, _set_vol_space_cmd(fn, config)))

            utils.run_cmds(cmds, env)
            cmds = []

        else:
            print "AddEdge seems to have been run already"

        sid = config['sid']
        plot_slice_fns = [(ae_e_n + '_e3', ae_s_n + '_e3', '%s_qa_e3.png' % sid),
                          (None, ae_e_n + '_' + ae_s_n + '_ec', '%s_qa_ec.png' % sid)]


        plot_slice_imgfns = ['%s/%s' % (refdir, fn) for fn in plot_slice_fns]
        if overwrite or not all(map(os.path.exists, plot_slice_imgfns)):
            slice_dims = [0, 1, 2]
            slice_pos = [.35, .45, .55, .65]
            for fns in plot_slice_fns:
                input_fns = []
                for i, fn in enumerate(fns):
                    if fn is not None:
                        fn = '%s/%s' % (refdir, fn)
                        if i <= 1:
                            fn += ext
                    input_fns.append(fn)

                fn1, fn2, fnout = input_fns
                if not os.path.exists(fnout):
                    _make_slice_plot(fn1, fn2, fnout)
                    print "QA Image saved to %s" % fnout
                else:
                    print "Already exists: %s" % fnout
        else:
            print "QA images already exist"



    # because AFNI uses RAI orientation but FreeSurfer LPI, make a new
    # affine transformation matrix in which the signs of
    # x and y coordinates are negated before and after the transformation
    matrixfn_LPI2RAI = '%s.A2E_LPI.1D' % ssalprefix
    if overwrite or not os.path.exists('%s/%s' % (refdir, matrixfn_LPI2RAI)):
        lpirai = '"MATRIX(-1,0,0,0,0,-1,0,0,0,0,1,0)"'
        cmd = ('cd %s; cat_matvec -ONELINE %s `cat_matvec -MATRIX %s` %s > %s' %
             (refdir, lpirai, matrixfn, lpirai, matrixfn_LPI2RAI))
        cmds.append(cmd)

    # apply transformation to surfaces
    [icolds, hemis] = _get_hemis_icolds(config)
    sumadir = config['sumadir']
    sumafiles = os.listdir(sumadir)


    origext = '.asc'
    ext = format2extension(config)
    tp = format2type(config)
    # process all hemispheres and ld values
    for icold in icolds:
        for hemi in hemis:
            pat = '%s%sh.?*%s' % (config['mi_icopat'] % icold, hemi, origext)
            for sumafile in sumafiles:
                if fnmatch.fnmatch(sumafile, pat):
                    if not sumafile.endswith(origext):
                        raise ValueError("%s does not end with %s" % (sumafile, origext))
                    #s = sumafile.split(".")
                    #s[len(s) - 2] += config['alsuffix'] # insert '_al' just before last dot
                    #alsumafile = ".".join(s)
                    extsumafile = sumafile[:-len(origext)]
                    alsumafile = extsumafile + config['alsuffix'] + ext

                    if config['overwrite'] or not os.path.exists('%s/%s' % (refdir, alsumafile)):
                        # now apply transformation
                        cmd = 'cd "%s";ConvertSurface -overwrite -i_fs %s/%s -o_%s ./%s -ixmat_1D %s' % \
                              (refdir, sumadir, sumafile, tp, alsumafile, matrixfn_LPI2RAI)
                        cmds.append(cmd)

                    # as of June 2012 copy the original sphere.reg (not aligned) as well
                    if sumafile == ('%s.sphere.reg%s' % (pat, ext)):
                        sumaout = '%s/%s' % (refdir, extsumafile + ext)
                        if config['overwrite'] or not os.path.exists(sumaout):
                            s = surf.read('%s/%s' % (sumadir, sumafile))
                            surf.write(s, sumaout)
                            #cmds.append('cp %s/%s %s/%s' % (sumadir, sumafile, refdir, sumafile))


        mapfn = (config['mi_icopat'] % icold) + config['hemimappingsuffix']
        srcpathfn = pathjoin(sumadir, mapfn)

        if os.path.exists(srcpathfn):
            trgpathfn = pathjoin(refdir, mapfn)
            if not os.path.exists(trgpathfn) or config['overwrite']:
                cmds.append('cp %s %s' % (srcpathfn, trgpathfn))

    utils.run_cmds(cmds, env)
Ejemplo n.º 12
0
def average_fs_asc_surfs(fn1, fn2, fnout):
    '''averages two surfaces'''
    surf1 = surf.read(fn1)
    surf2 = surf.read(fn2)
    surfavg = surf1 * .5 + surf2 * .5
    surf.write(fnout, surfavg)
Ejemplo n.º 13
0
def average_fs_asc_surfs(fn1, fn2, fnout):
    """averages two surfaces"""
    surf1 = surf.read(fn1)
    surf2 = surf.read(fn2)
    surfavg = surf1 * 0.5 + surf2 * 0.5
    surf.write(fnout, surfavg)
Ejemplo n.º 14
0
    def test_surf_voxel_selection(self):
        vol_shape = (10, 10, 10)
        vol_affine = np.identity(4)
        vol_affine[0, 0] = vol_affine[1, 1] = vol_affine[2, 2] = 5

        vg = volgeom.VolGeom(vol_shape, vol_affine)

        density = 10

        outer = surf.generate_sphere(density) * 25. + 15
        inner = surf.generate_sphere(density) * 20. + 15

        vs = volsurf.VolSurfMaximalMapping(vg, outer, inner)

        nv = outer.nvertices

        # select under variety of parameters
        # parameters are distance metric (dijkstra or euclidean),
        # radius, and number of searchlight  centers
        params = [('d', 1., 10), ('d', 1., 50), ('d', 1., 100), ('d', 2., 100),
                  ('e', 2., 100), ('d', 2., 100), ('d', 20, 100),
                  ('euclidean', 5, None), ('dijkstra', 10, None)]

        # function that indicates for which parameters the full test is run
        test_full = lambda x:len(x[0]) > 1 or x[2] == 100

        expected_labs = ['grey_matter_position',
                         'center_distances']

        voxcount = []
        tested_double_features = False
        for param in params:
            distance_metric, radius, ncenters = param
            srcs = range(0, nv, nv // (ncenters or nv))
            sel = surf_voxel_selection.voxel_selection(vs, radius,
                                            source_surf_nodes=srcs,
                                            distance_metric=distance_metric)

            # see how many voxels were selected
            vg = sel.volgeom
            datalin = np.zeros((vg.nvoxels, 1))

            mp = sel
            for k, idxs in mp.iteritems():
                if idxs is not None:
                    datalin[idxs] = 1

            voxcount.append(np.sum(datalin))

            if test_full(param):
                assert_equal(np.sum(datalin), np.sum(sel.get_mask()))

                assert_true(len('%s%r' % (sel, sel)) > 0)

                # see if voxels containing inner and outer
                # nodes were selected
                for sf in [inner, outer]:
                    for k, idxs in mp.iteritems():
                        xyz = np.reshape(sf.vertices[k, :], (1, 3))
                        linidx = vg.xyz2lin(xyz)

                        # only required if xyz is actually within the volume
                        assert_equal(linidx in idxs, vg.contains_lin(linidx))

                # check that it has all the attributes
                labs = sel.aux_keys()

                assert_true(all([lab in labs for lab in expected_labs]))


                if externals.exists('h5py'):
                    # some I/O testing
                    fd, fn = tempfile.mkstemp('.h5py', 'test'); os.close(fd)
                    h5save(fn, sel)

                    sel2 = h5load(fn)
                    os.remove(fn)

                    assert_equal(sel, sel2)
                else:
                    sel2 = sel

                # check that mask is OK even after I/O
                assert_array_equal(sel.get_mask(), sel2.get_mask())


                # test I/O with surfaces
                # XXX the @tempfile decorator only supports a single filename
                #     hence this method does not use it
                fd, outerfn = tempfile.mkstemp('outer.asc', 'test'); os.close(fd)
                fd, innerfn = tempfile.mkstemp('inner.asc', 'test'); os.close(fd)
                fd, volfn = tempfile.mkstemp('vol.nii', 'test'); os.close(fd)

                surf.write(outerfn, outer, overwrite=True)
                surf.write(innerfn, inner, overwrite=True)

                img = sel.volgeom.get_empty_nifti_image()
                img.to_filename(volfn)

                sel3 = surf_voxel_selection.run_voxel_selection(radius, volfn, innerfn,
                                outerfn, source_surf_nodes=srcs,
                                distance_metric=distance_metric)

                outer4 = surf.read(outerfn)
                inner4 = surf.read(innerfn)
                vsm4 = vs = volsurf.VolSurfMaximalMapping(vg, inner4, outer4)

                # check that two ways of voxel selection match
                sel4 = surf_voxel_selection.voxel_selection(vsm4, radius,
                                                    source_surf_nodes=srcs,
                                                    distance_metric=distance_metric)

                assert_equal(sel3, sel4)

                os.remove(outerfn)
                os.remove(innerfn)
                os.remove(volfn)


                # compare sel3 with other selection results
                # NOTE: which voxels are precisely selected by sel can be quite
                #       off from those in sel3, as writing the surfaces imposes
                #       rounding errors and the sphere is very symmetric, which
                #       means that different neighboring nodes are selected
                #       to select a certain number of voxels.
                sel3cmp_difference_ratio = [(sel, .2), (sel4, 0.)]
                for selcmp, ratio in sel3cmp_difference_ratio:
                    nunion = ndiff = 0

                    for k in selcmp.keys():
                        p = set(sel3.get(k))
                        q = set(selcmp.get(k))
                        nunion += len(p.union(q))
                        ndiff += len(p.symmetric_difference(q))

                    assert_true(float(ndiff) / float(nunion) <= ratio)

                # check searchlight call
                # as of late Aug 2012, this is with the fancy query engine
                # as implemented by Yarik

                mask = sel.get_mask()
                keys = None if ncenters is None else sel.keys()

                dset_data = np.reshape(np.arange(vg.nvoxels), vg.shape)
                dset_img = nb.Nifti1Image(dset_data, vg.affine)
                dset = fmri_dataset(samples=dset_img, mask=mask)

                qe = queryengine.SurfaceVerticesQueryEngine(sel,
                                    # you can optionally add additional
                                    # information about each near-disk-voxels
                                    add_fa=['center_distances',
                                            'grey_matter_position'])

                # test i/o ensuring that when loading it is still trained
                if externals.exists('h5py'):
                    fd, qefn = tempfile.mkstemp('qe.hdf5', 'test'); os.close(fd)
                    h5save(qefn, qe)
                    qe = h5load(qefn)
                    os.remove(qefn)


                assert_false('ERROR' in repr(qe))   #  to check if repr works
                voxelcounter = _Voxel_Count_Measure()
                searchlight = Searchlight(voxelcounter, queryengine=qe, roi_ids=keys, nproc=1,
                                          enable_ca=['roi_feature_ids', 'roi_center_ids'])
                sl_dset = searchlight(dset)

                selected_count = sl_dset.samples[0, :]
                mp = sel
                for i, k in enumerate(sel.keys()):
                    # check that number of selected voxels matches
                    assert_equal(selected_count[i], len(mp[k]))


                assert_equal(searchlight.ca.roi_center_ids, sel.keys())

                assert_array_equal(sl_dset.fa['center_ids'], qe.ids)

                # check nearest node is *really* the nearest node

                allvx = sel.get_targets()
                intermediate = outer * .5 + inner * .5

                for vx in allvx:
                    nearest = sel.target2nearest_source(vx)

                    xyz = intermediate.vertices[nearest, :]
                    sqsum = np.sum((xyz - intermediate.vertices) ** 2, 1)

                    idx = np.argmin(sqsum)
                    assert_equal(idx, nearest)

                if not tested_double_features:           # test only once
                    # see if we have multiple features for the same voxel, we would get them all
                    dset1 = dset.copy()
                    dset1.fa['dset'] = [1]
                    dset2 = dset.copy()
                    dset2.fa['dset'] = [2]
                    dset_ = hstack((dset1, dset2), 'drop_nonunique')
                    dset_.sa = dset1.sa
                    #dset_.a.imghdr = dset1.a.imghdr
                    assert_true('imghdr' in dset_.a.keys())
                    assert_equal(dset_.a['imghdr'].value, dset1.a['imghdr'].value)
                    roi_feature_ids = searchlight.ca.roi_feature_ids
                    sl_dset_ = searchlight(dset_)
                    # and we should get twice the counts
                    assert_array_equal(sl_dset_.samples, sl_dset.samples * 2)

                    # compare old and new roi_feature_ids
                    assert(len(roi_feature_ids) == len(searchlight.ca.roi_feature_ids))
                    nfeatures = dset.nfeatures
                    for old, new in zip(roi_feature_ids,
                                        searchlight.ca.roi_feature_ids):
                        # each new ids should comprise of old ones + (old + nfeatures)
                        # since we hstack'ed two datasets
                        assert_array_equal(np.hstack([(x, x + nfeatures) for x in old]),
                                           new)
                    tested_double_features = True

        # check whether number of voxels were selected is as expected
        expected_voxcount = [22, 93, 183, 183, 183, 183, 183, 183, 183]

        assert_equal(voxcount, expected_voxcount)
Ejemplo n.º 15
0
def average_fs_asc_surfs(fn1, fn2, fnout):
    '''averages two surfaces'''
    surf1 = surf.read(fn1)
    surf2 = surf.read(fn2)
    surfavg = surf1 * .5 + surf2 * .5
    surf.write(fnout, surfavg)
Ejemplo n.º 16
0
    def test_surf_gifti(self, fn):
        # From section 14.4 in GIFTI Surface Data Format Version 1.0
        # (with some adoptions)

        test_data = '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE GIFTI SYSTEM "http://www.nitrc.org/frs/download.php/1594/gifti.dtd">
<GIFTI
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://www.nitrc.org/frs/download.php/1303/GIFTI_Caret.xsd"
  Version="1.0"
  NumberOfDataArrays="2">
<MetaData>
  <MD>
    <Name><![CDATA[date]]></Name>
    <Value><![CDATA[Thu Nov 15 09:05:22 2007]]></Value>
  </MD>
</MetaData>
<LabelTable/>
<DataArray Intent="NIFTI_INTENT_POINTSET"
  DataType="NIFTI_TYPE_FLOAT32"
  ArrayIndexingOrder="RowMajorOrder"
  Dimensionality="2"
  Dim0="4"
  Dim1="3"
  Encoding="ASCII"
  Endian="LittleEndian"
  ExternalFileName=""
  ExternalFileOffset="">
<CoordinateSystemTransformMatrix>
  <DataSpace><![CDATA[NIFTI_XFORM_TALAIRACH]]></DataSpace>
  <TransformedSpace><![CDATA[NIFTI_XFORM_TALAIRACH]]></TransformedSpace>
  <MatrixData>
    1.000000 0.000000 0.000000 0.000000
    0.000000 1.000000 0.000000 0.000000
    0.000000 0.000000 1.000000 0.000000
    0.000000 0.000000 0.000000 1.000000
  </MatrixData>
</CoordinateSystemTransformMatrix>
<Data>
  10.5 0 0
  0 20.5 0
  0 0 30.5
  0 0 0
</Data>
</DataArray>
<DataArray Intent="NIFTI_INTENT_TRIANGLE"
  DataType="NIFTI_TYPE_INT32"
  ArrayIndexingOrder="RowMajorOrder"
  Dimensionality="2"
  Dim0="4"
  Dim1="3"
  Encoding="ASCII"
  Endian="LittleEndian"
  ExternalFileName="" ExternalFileOffset="">
<Data>
0 1 2
1 2 3
0 1 3
0 2 3
</Data>
</DataArray>
</GIFTI>'''

        with open(fn, 'w') as f:
            f.write(test_data)

        # test I/O
        s = surf.read(fn)
        surf.write(fn, s)
        s = surf.read(fn)

        v = np.zeros((4, 3))
        v[0, 0] = 10.5
        v[1, 1] = 20.5
        v[2, 2] = 30.5

        f = np.asarray([[0, 1, 2], [1, 2, 3], [0, 1, 3], [0, 2, 3]],
                       dtype=np.int32)

        assert_array_equal(s.vertices, v)
        assert_array_equal(s.faces, f)
Ejemplo n.º 17
0
def run_alignment(config, env):
    '''Aligns anat (which is assumed to be aligned with EPI data) to FreeSurfer SurfVol

    This function strips the anatomicals (by default), then uses align_epi_anat.py
    to estimate the alignment, then applies this transformation to the non-skull-stripped
    SurfVol and also to the surfaces. Some alignment headers will be nuked'''
    overwrite = config['overwrite']
    alignsuffix = config['al2expsuffix']
    refdir = config['refdir']

    fullext = config['outvol_fullext']
    ext = config['outvol_ext']

    if config['sid'] is None:
        raise ValueError('Need sid')

    cmds = []
    if not os.path.exists(config['refdir']):
        cmds.append('mkdir %(refdir)s' % config)

    # two volumes may have to be stripped: the inpput anatomical, and the surfvol.
    # put them in a list here and process them similarly
    surfvol = '%(refdir)s/%(sid)s_SurfVol%(outvol_fullext)s' % config
    surfvol_ss = '%(refdir)s/%(sid)s_SurfVol%(sssuffix)s%(outvol_fullext)s' % config

    e_p, e_n, _, _ = utils.afni_fileparts(config['expvol'])
    if config['expvol_ss']:
        e_n = '%s%s' % (e_n, config['sssuffix'])
    expvol = '%s/%s%s' % (refdir, e_n, fullext)

    volsin = [surfvol_ss, expvol]
    for volin in volsin:
        if not os.path.exists(volin):
            raise ValueError('File %s does not exist' % volin)

    a_n = utils.afni_fileparts(volsin[0])[1]  # surfvol input root name
    ssalprefix = '%s%s' % (a_n, alignsuffix)

    unity = "1 0 0 0 0 1 0 0 0 0 1 0"  # we all like unity, don't we?

    fullmatrixfn = '%s_mat.aff12.1D' % ssalprefix
    aloutfns = ['%s%s' % (ssalprefix, fullext),
                fullmatrixfn]  # expected output files if alignment worked
    if config['overwrite'] or not all(
        [os.path.exists('%s/%s' % (refdir, f)) for f in aloutfns]):
        alignedfn = '%s/%s%s' % (refdir, ssalprefix, fullext)

        if config['identity']:
            fullmatrix_content = '"MATRIX(%s)"' % unity.replace(" ", ",")

            cmd = 'cd "%s"; cat_matvec %s > %s; 3dcopy -overwrite %s%s %s%s%s' % (
                refdir, fullmatrix_content, fullmatrixfn, a_n, ext, a_n,
                alignsuffix, ext)
        else:
            # use different inputs depending on whether expvol is EPI or ANAT
            twovolpat = (
                '-anat %s -epi %s -anat2epi -epi_base 0 -anat_has_skull no -epi_strip None'
                if config['isepi'] else
                '-dset1 %s -dset2 %s -dset1to2 -dset1_strip None -dset2_strip None'
            )
            # use this pattern to generate a suffix
            twovolsuffix = twovolpat % (volsin[0], volsin[1])

            aea_opts = config['aea_opts']
            if config['template']:
                aea_opts += " -Allineate_opts '-maxrot 10 -maxshf 10 -maxscl 1.5'"
            # align_epi_anat.py
            cmd = 'cd "%s"; align_epi_anat.py -overwrite -suffix %s %s %s' % (
                refdir, alignsuffix, twovolsuffix, aea_opts)

        cmds.append(cmd)

        cmds.append(_set_vol_space_cmd(alignedfn, config))

        utils.run_cmds(cmds, env)

    else:
        print "Alignment already done - skipping"

        # run these commands first, then check if everything worked properly

    cmds = []

    # see if the expected transformation file was found
    if not config['identity'] and not os.path.exists('%s/%s' %
                                                     (refdir, fullmatrixfn)):
        raise Exception("Could not find %s in %s" % (fullmatrixfn, refdir))

    # now make a 3x4 matrix
    matrixfn = '%s%s.A2E.1D' % (a_n, alignsuffix)
    if overwrite or not os.path.exists('%s/%s' % (refdir, matrixfn)):
        cmds.append('cd "%s"; cat_matvec %s > %s || exit 1' %
                    (refdir, fullmatrixfn, matrixfn))

    # make an aligned, non-skullstripped version of SurfVol in refdir
    alprefix = '%s_SurfVol%s' % (config['sid'], alignsuffix)
    svalignedfn = '%s/%s%s' % (refdir, alprefix, fullext)

    newgrid = 1  # size of anatomical grid in mm. We'll have to resample, otherwise 3dWarp does
    # not respect the corners of the volume (as of April 2012)

    if overwrite or not os.path.exists(svalignedfn):
        #if not config['fs_sid']:
        #    raise ValueError("Don't have a freesurfer subject id - cannot continue")

        #surfvolfn = '%s/%s_SurfVol+orig' % (config['sumadir'], config['fs_sid'])
        surfvolfn = '%s/T1.nii' % config['sumadir']
        cmds.append(
            'cd "%s";3dWarp -overwrite -newgrid %f -matvec_out2in `cat_matvec -MATRIX %s` -prefix ./%s %s'
            % (refdir, newgrid, matrixfn, alprefix, surfvolfn))
        cmds.append(
            _set_vol_space_cmd('%s/%s+orig' % (refdir, alprefix), config))

    else:
        print '%s already exists - skipping Warp' % svalignedfn

    utils.run_cmds(cmds, env)
    cmds = []

    # nuke afni headers
    headernukefns = ['%s%s' % (f, fullext) for f in [ssalprefix, alprefix]]
    headernukefields = [
        'ALLINEATE_MATVEC_B2S_000000', 'ALLINEATE_MATVEC_S2B_000000',
        'WARPDRIVE_MATVEC_FOR_000000', 'WARPDRIVE_MATVEC_INV_000000'
    ]

    for fn in headernukefns:
        for field in headernukefields:
            # nuke transformation - otherwise AFNI does this unwanted transformation for us
            fullfn = '%s/%s' % (refdir, fn)

            if not (os.path.exists(fullfn) or config['identity']):
                raise ValueError("File %r does not exist" % fullfn)

            refitcmd = "3drefit -atrfloat %s '%s' %s" % (field, unity, fn)

            # only refit if not already in AFNI history (which is stored in HEADfile)
            cmd = 'cd "%s"; m=`grep "%s" %s | wc -w`; if [ $m -eq 0 ]; then %s; else echo "File %s seems already 3drefitted"; fi' % (
                refdir, refitcmd, fn, refitcmd, fn)
            cmds.append(cmd)
    utils.run_cmds('; '.join(cmds), env)
    cmds = []

    # run AddEdge so that volumes can be inspected visually for alignment
    if config['AddEdge']:
        use_ss = config['expvol_ss']

        # ae_{e,s}_n are AddEdge names for expvol and surfvol
        ae_e_n = utils.afni_fileparts(config['expvol'])[1]
        if use_ss:
            ae_e_n += config['sssuffix']
        ae_s_n = ssalprefix  #if use_ss else alprefix

        # *_ne have the output extension as well
        ae_e_ne = ae_e_n + ext
        ae_s_ne = ae_s_n + ext

        addedge_fns = ['%s/_ae.ExamineList.log' % refdir]

        exts = ['HEAD', 'BRIK']
        orig_ext = '+orig'
        addedge_rootfns = [
            '%s_%s%%s' % (ae_e_n, postfix)
            for postfix in ['e3', 'ec', ae_s_n + '_ec']
        ]
        addedge_rootfns.extend(
            ['%s_%s%%s' % (ae_s_n, postfix) for postfix in ['e3', 'ec']])

        addedge_fns_pat = [
            '%s.%s' % (fn, e) for fn in addedge_rootfns for e in exts
        ]

        addegde_pathfns_orig = map(lambda x: os.path.join(refdir, x % '+orig'),
                                   addedge_fns_pat) + addedge_fns
        addegde_pathfns_ext = map(lambda x: os.path.join(refdir, x % ext),
                                  addedge_fns_pat)
        addegde_exists = map(os.path.exists, addegde_pathfns_ext)
        if overwrite or not all(addegde_exists):
            ae_ns = (ae_e_n, ae_s_n)

            cmds.extend(
                map(lambda fn: 'if [ -e "%s" ]; then rm "%s"; fi' % (fn, fn),
                    addegde_pathfns_orig + addegde_pathfns_ext))
            cmds.append(';'.join(['cd %s' % refdir] + [
                _convert_vol_space_to_orig_cmd('%s/%s%s' % (refdir, n, ext))
                for n in ae_ns
            ] + ['\@AddEdge %s+orig %s+orig' % ae_ns]))

            set_space_fns = addegde_pathfns_orig + [
                '%s/%s%s.%s' % (refdir, fn, orig_ext, exts[0]) for fn in ae_ns
            ]

            for fn in set_space_fns:  #['%s/%s' % (refdir, fn % orig_ext) for fn in addedge_fns_pat]:
                if fn.endswith('.log'):
                    continue
                cmds.append('if [ -e %s ]; then %s; fi' %
                            (fn, _set_vol_space_cmd(fn, config)))

            utils.run_cmds(cmds, env)
            cmds = []

        else:
            print "AddEdge seems to have been run already"

        sid = config['sid']
        plot_slice_fns = [
            (ae_e_n + '_e3', ae_s_n + '_e3', '%s_qa_e3.png' % sid),
            (None, ae_e_n + '_' + ae_s_n + '_ec', '%s_qa_ec.png' % sid)
        ]

        plot_slice_imgfns = ['%s/%s' % (refdir, fn) for fn in plot_slice_fns]
        if overwrite or not all(map(os.path.exists, plot_slice_imgfns)):
            slice_dims = [0, 1, 2]
            slice_pos = [.35, .45, .55, .65]
            for fns in plot_slice_fns:
                input_fns = []
                for i, fn in enumerate(fns):
                    if fn is not None:
                        fn = '%s/%s' % (refdir, fn)
                        if i <= 1:
                            fn += ext
                    input_fns.append(fn)

                fn1, fn2, fnout = input_fns
                if not os.path.exists(fnout):
                    _make_slice_plot(fn1, fn2, fnout)
                    print "QA Image saved to %s" % fnout
                else:
                    print "Already exists: %s" % fnout
        else:
            print "QA images already exist"

    # because AFNI uses RAI orientation but FreeSurfer LPI, make a new
    # affine transformation matrix in which the signs of
    # x and y coordinates are negated before and after the transformation
    matrixfn_LPI2RAI = '%s.A2E_LPI.1D' % ssalprefix
    if overwrite or not os.path.exists('%s/%s' % (refdir, matrixfn_LPI2RAI)):
        lpirai = '"MATRIX(-1,0,0,0,0,-1,0,0,0,0,1,0)"'
        cmd = (
            'cd %s; cat_matvec -ONELINE %s `cat_matvec -MATRIX %s` %s > %s' %
            (refdir, lpirai, matrixfn, lpirai, matrixfn_LPI2RAI))
        cmds.append(cmd)

    # apply transformation to surfaces
    [icolds, hemis] = _get_hemis_icolds(config)
    sumadir = config['sumadir']
    sumafiles = os.listdir(sumadir)

    origext = '.asc'
    ext = format2extension(config)
    tp = format2type(config)
    # process all hemispheres and ld values
    for icold in icolds:
        for hemi in hemis:
            pat = '%s%sh.?*%s' % (config['mi_icopat'] % icold, hemi, origext)
            for sumafile in sumafiles:
                if fnmatch.fnmatch(sumafile, pat):
                    if not sumafile.endswith(origext):
                        raise ValueError("%s does not end with %s" %
                                         (sumafile, origext))
                    #s = sumafile.split(".")
                    #s[len(s) - 2] += config['alsuffix'] # insert '_al' just before last dot
                    #alsumafile = ".".join(s)
                    extsumafile = sumafile[:-len(origext)]
                    alsumafile = extsumafile + config['alsuffix'] + ext

                    if config['overwrite'] or not os.path.exists(
                            '%s/%s' % (refdir, alsumafile)):
                        # now apply transformation
                        cmd = 'cd "%s";ConvertSurface -overwrite -i_fs %s/%s -o_%s ./%s -ixmat_1D %s' % \
                              (refdir, sumadir, sumafile, tp, alsumafile, matrixfn_LPI2RAI)
                        cmds.append(cmd)

                    # as of June 2012 copy the original sphere.reg (not aligned) as well
                    if sumafile == ('%s.sphere.reg%s' % (pat, ext)):
                        sumaout = '%s/%s' % (refdir, extsumafile + ext)
                        if config['overwrite'] or not os.path.exists(sumaout):
                            s = surf.read('%s/%s' % (sumadir, sumafile))
                            surf.write(s, sumaout)
                            #cmds.append('cp %s/%s %s/%s' % (sumadir, sumafile, refdir, sumafile))

        mapfn = (config['mi_icopat'] % icold) + config['hemimappingsuffix']
        srcpathfn = os.path.join(sumadir, mapfn)

        if os.path.exists(srcpathfn):
            trgpathfn = os.path.join(refdir, mapfn)
            if not os.path.exists(trgpathfn) or config['overwrite']:
                cmds.append('cp %s %s' % (srcpathfn, trgpathfn))

    utils.run_cmds(cmds, env)
Ejemplo n.º 18
0
    def test_surf_voxel_selection(self):
        vol_shape = (10, 10, 10)
        vol_affine = np.identity(4)
        vol_affine[0, 0] = vol_affine[1, 1] = vol_affine[2, 2] = 5

        vg = volgeom.VolGeom(vol_shape, vol_affine)

        density = 10

        outer = surf.generate_sphere(density) * 25. + 15
        inner = surf.generate_sphere(density) * 20. + 15

        vs = volsurf.VolSurfMaximalMapping(vg, outer, inner)

        nv = outer.nvertices

        # select under variety of parameters
        # parameters are distance metric (dijkstra or euclidean),
        # radius, and number of searchlight  centers
        params = [('d', 1., 10), ('d', 1., 50), ('d', 1., 100), ('d', 2., 100),
                  ('e', 2., 100), ('d', 2., 100), ('d', 20, 100),
                  ('euclidean', 5, None), ('dijkstra', 10, None)]

        # function that indicates for which parameters the full test is run
        test_full = lambda x: len(x[0]) > 1 or x[2] == 100

        expected_labs = ['grey_matter_position', 'center_distances']

        voxcount = []
        tested_double_features = False
        for param in params:
            distance_metric, radius, ncenters = param
            srcs = range(0, nv, nv // (ncenters or nv))
            sel = surf_voxel_selection.voxel_selection(
                vs,
                radius,
                source_surf_nodes=srcs,
                distance_metric=distance_metric)

            # see how many voxels were selected
            vg = sel.volgeom
            datalin = np.zeros((vg.nvoxels, 1))

            mp = sel
            for k, idxs in mp.iteritems():
                if idxs is not None:
                    datalin[idxs] = 1

            voxcount.append(np.sum(datalin))

            if test_full(param):
                assert_equal(np.sum(datalin), np.sum(sel.get_mask()))

                assert_true(len('%s%r' % (sel, sel)) > 0)

                # see if voxels containing inner and outer
                # nodes were selected
                for sf in [inner, outer]:
                    for k, idxs in mp.iteritems():
                        xyz = np.reshape(sf.vertices[k, :], (1, 3))
                        linidx = vg.xyz2lin(xyz)

                        # only required if xyz is actually within the volume
                        assert_equal(linidx in idxs, vg.contains_lin(linidx))

                # check that it has all the attributes
                labs = sel.aux_keys()

                assert_true(all([lab in labs for lab in expected_labs]))

                if externals.exists('h5py'):
                    # some I/O testing
                    fd, fn = tempfile.mkstemp('.h5py', 'test')
                    os.close(fd)
                    h5save(fn, sel)

                    sel2 = h5load(fn)
                    os.remove(fn)

                    assert_equal(sel, sel2)
                else:
                    sel2 = sel

                # check that mask is OK even after I/O
                assert_array_equal(sel.get_mask(), sel2.get_mask())

                # test I/O with surfaces
                # XXX the @tempfile decorator only supports a single filename
                #     hence this method does not use it
                fd, outerfn = tempfile.mkstemp('outer.asc', 'test')
                os.close(fd)
                fd, innerfn = tempfile.mkstemp('inner.asc', 'test')
                os.close(fd)
                fd, volfn = tempfile.mkstemp('vol.nii', 'test')
                os.close(fd)

                surf.write(outerfn, outer, overwrite=True)
                surf.write(innerfn, inner, overwrite=True)

                img = sel.volgeom.get_empty_nifti_image()
                img.to_filename(volfn)

                sel3 = surf_voxel_selection.run_voxel_selection(
                    radius,
                    volfn,
                    innerfn,
                    outerfn,
                    source_surf_nodes=srcs,
                    distance_metric=distance_metric)

                outer4 = surf.read(outerfn)
                inner4 = surf.read(innerfn)
                vsm4 = vs = volsurf.VolSurfMaximalMapping(vg, inner4, outer4)

                # check that two ways of voxel selection match
                sel4 = surf_voxel_selection.voxel_selection(
                    vsm4,
                    radius,
                    source_surf_nodes=srcs,
                    distance_metric=distance_metric)

                assert_equal(sel3, sel4)

                os.remove(outerfn)
                os.remove(innerfn)
                os.remove(volfn)

                # compare sel3 with other selection results
                # NOTE: which voxels are precisely selected by sel can be quite
                #       off from those in sel3, as writing the surfaces imposes
                #       rounding errors and the sphere is very symmetric, which
                #       means that different neighboring nodes are selected
                #       to select a certain number of voxels.
                sel3cmp_difference_ratio = [(sel, .2), (sel4, 0.)]
                for selcmp, ratio in sel3cmp_difference_ratio:
                    nunion = ndiff = 0

                    for k in selcmp.keys():
                        p = set(sel3.get(k))
                        q = set(selcmp.get(k))
                        nunion += len(p.union(q))
                        ndiff += len(p.symmetric_difference(q))

                    assert_true(float(ndiff) / float(nunion) <= ratio)

                # check searchlight call
                # as of late Aug 2012, this is with the fancy query engine
                # as implemented by Yarik

                mask = sel.get_mask()
                keys = None if ncenters is None else sel.keys()

                dset_data = np.reshape(np.arange(vg.nvoxels), vg.shape)
                dset_img = nb.Nifti1Image(dset_data, vg.affine)
                dset = fmri_dataset(samples=dset_img, mask=mask)

                qe = queryengine.SurfaceVerticesQueryEngine(
                    sel,
                    # you can optionally add additional
                    # information about each near-disk-voxels
                    add_fa=['center_distances', 'grey_matter_position'])

                # test i/o ensuring that when loading it is still trained
                if externals.exists('h5py'):
                    fd, qefn = tempfile.mkstemp('qe.hdf5', 'test')
                    os.close(fd)
                    h5save(qefn, qe)
                    qe = h5load(qefn)
                    os.remove(qefn)

                assert_false('ERROR' in repr(qe))  #  to check if repr works
                voxelcounter = _Voxel_Count_Measure()
                searchlight = Searchlight(
                    voxelcounter,
                    queryengine=qe,
                    roi_ids=keys,
                    nproc=1,
                    enable_ca=['roi_feature_ids', 'roi_center_ids'])
                sl_dset = searchlight(dset)

                selected_count = sl_dset.samples[0, :]
                mp = sel
                for i, k in enumerate(sel.keys()):
                    # check that number of selected voxels matches
                    assert_equal(selected_count[i], len(mp[k]))

                assert_equal(searchlight.ca.roi_center_ids, sel.keys())

                assert_array_equal(sl_dset.fa['center_ids'], qe.ids)

                # check nearest node is *really* the nearest node

                allvx = sel.get_targets()
                intermediate = outer * .5 + inner * .5

                for vx in allvx:
                    nearest = sel.target2nearest_source(vx)

                    xyz = intermediate.vertices[nearest, :]
                    sqsum = np.sum((xyz - intermediate.vertices)**2, 1)

                    idx = np.argmin(sqsum)
                    assert_equal(idx, nearest)

                if not tested_double_features:  # test only once
                    # see if we have multiple features for the same voxel, we would get them all
                    dset1 = dset.copy()
                    dset1.fa['dset'] = [1]
                    dset2 = dset.copy()
                    dset2.fa['dset'] = [2]
                    dset_ = hstack((dset1, dset2), 'drop_nonunique')
                    dset_.sa = dset1.sa
                    # dset_.a.imghdr = dset1.a.imghdr
                    assert_true('imghdr' in dset_.a.keys())
                    assert_equal(dset_.a['imghdr'].value,
                                 dset1.a['imghdr'].value)
                    roi_feature_ids = searchlight.ca.roi_feature_ids
                    sl_dset_ = searchlight(dset_)
                    # and we should get twice the counts
                    assert_array_equal(sl_dset_.samples, sl_dset.samples * 2)

                    # compare old and new roi_feature_ids
                    assert (len(roi_feature_ids) == len(
                        searchlight.ca.roi_feature_ids))
                    nfeatures = dset.nfeatures
                    for old, new in zip(roi_feature_ids,
                                        searchlight.ca.roi_feature_ids):
                        # each new ids should comprise of old ones + (old + nfeatures)
                        # since we hstack'ed two datasets
                        assert_array_equal(
                            np.hstack([(x, x + nfeatures) for x in old]), new)
                    tested_double_features = True

        # check whether number of voxels were selected is as expected
        expected_voxcount = [22, 93, 183, 183, 183, 183, 183, 183, 183]

        assert_equal(voxcount, expected_voxcount)
Ejemplo n.º 19
0
def hemi_pairs_add_views(spec_both,
                         state,
                         ext,
                         directory=None,
                         overwrite=False):
    '''adds views for medial, superior, inferior, anterior, posterior viewing
    of two surfaces together. Also generates these surfaces'''

    spec_left, spec_right = spec_both[0], spec_both[1]

    if directory is None:
        directory = os.path.curdir

    if not spec_left.same_states(spec_right):
        raise ValueError('Incompatible states for left and right')

    #views = collections.OrderedDict(m='medial', s='superior', i='inferior', a='anterior', p='posterior')
    # for compatibility use a normal dict

    if state == 'inflated':
        views = dict(m='medial',
                     s='superior',
                     i='inferior',
                     a='anterior',
                     p='posterior')
        viewkeys = ['m', 's', 'i', 'a', 'p']
    else:
        views = dict(m='medial')
        viewkeys = 'm'

    spec_both = [spec_left, spec_right]
    spec_both_new = map(copy.deepcopy, spec_both)

    for view in viewkeys:
        longname = views[view]
        oldfns = []
        newfns = []
        for i, spec in enumerate(spec_both):

            idxdef = spec.find_surface_from_state(state)
            if len(idxdef) != 1:
                raise ValueError('Not unique surface with state %s' % state)
            surfidx, surfdef = idxdef[0]

            # take whichever is there (in order of preference)
            # shame that python has no builtin foldr
            surfnamelabels = ['SurfaceName', 'FreeSurferSurface']
            for surfnamelabel in surfnamelabels:
                surfname = surfdef.get(surfnamelabel)
                if not surfname is None:
                    break
            #surfname = utils.foldr(surfdef.get, None, surfnamelabels)

            fn = os.path.join(directory, surfname)
            if not os.path.exists(fn):
                raise ValueError("File not found: %s" % fn)

            if not surfname.endswith(ext):
                raise ValueError('Expected extension %s for %s' % (ext, fn))
            oldfns.append(fn)  # store old name

            shortfn = surfname[:-(len(ext))]
            newsurfname = '%s%s%s%s' % (shortfn, _COMPREFIX, longname, ext)
            newfn = os.path.join(directory, newsurfname)

            newsurfdef = copy.deepcopy(surfdef)

            # ensure no naming cnoflicts
            for surfnamelabel in surfnamelabels:
                if surfnamelabel in newsurfdef:
                    newsurfdef.pop(surfnamelabel)
            newsurfdef['SurfaceName'] = newsurfname
            newsurfdef['SurfaceState'] = '%s%s%s' % (_COMPREFIX, view, state)
            spec_both_new[i].add_surface(newsurfdef)
            newfns.append(newfn)

        if all(map(os.path.exists, newfns)) and not overwrite:
            print "Output already exist for %s" % longname
        else:
            surf_left, surf_right = map(surf.read, oldfns)
            surf_both_moved = surf.reposition_hemisphere_pairs(
                surf_left, surf_right, view)

            for fn, surf_ in zip(newfns, surf_both_moved):
                surf.write(fn, surf_, overwrite)
                print "Written %s" % fn

    return tuple(spec_both_new)