示例#1
0
def test_summary():

    fslatlases.rescanAtlases()

    adescs  = fslatlases.listAtlases()
    capture = CaptureStdout()

    for desc in adescs:

        tests = [desc.atlasID, desc.name]

        for test in tests:

            capture.reset()

            with capture:
                fslatlasq.main(['summary', test])

            stdout = capture.stdout

            assert desc.atlasID   in stdout
            assert desc.name      in stdout
            assert desc.specPath  in stdout
            assert desc.atlasType in stdout

            for image in it.chain(desc.images, desc.summaryImages):
                assert image in stdout

            for label in desc.labels:
                assert label.name in stdout
示例#2
0
    def __loadAtlas(self):
        """Calls the :func:`loadAtlas` function. """

        if len(atlases.listAtlases()) == 0:
            atlases.rescanAtlases()

        loadAtlas(self.__frame)
示例#3
0
def test_list():

    fslatlases.rescanAtlases()

    adescs  = fslatlases.listAtlases()
    capture = CaptureStdout()

    tests     = ['list', 'list --extended']
    extendeds = [False, True]

    for test, extended in zip(tests, extendeds):
        capture.reset()

        with capture:
            fslatlasq.main(test.split())

        stdout = capture.stdout

        for desc in adescs:
            assert desc.atlasID in stdout
            assert desc.name    in stdout

            assert (desc.specPath in stdout) == extended

            for image in it.chain(desc.images, desc.summaryImages):
                assert (image in stdout) == extended
                assert (image in stdout) == extended
示例#4
0
def _random_atlas(atype, res, summary=False):

    if atype == 'prob':
        atype = 'probabilistic'

    atlases = fslatlases.listAtlases()
    atlases = [a for a in atlases if a.atlasType == atype]
    desc = atlases[np.random.randint(0, len(atlases))]
    return _get_atlas(desc.atlasID, res, summary)
示例#5
0
def identifyAtlas(idOrName):
    """Given a partial atlas ID or name, tries to find an atlas which
    uniquely matches it.
    """

    # TODO Use difflib or some fuzzy matching library?

    idOrName = idOrName.lower().strip()
    atlases = fslatlases.listAtlases()

    allNames = [a.name.lower() for a in atlases]
    allIDs = [a.atlasID.lower() for a in atlases]

    # First test for an exact match
    nameMatches = [idOrName == n for n in allNames]
    idMatches = [idOrName == i for i in allIDs]

    nameMatches = [i for i in range(len(nameMatches)) if nameMatches[i]]
    idMatches = [i for i in range(len(idMatches)) if idMatches[i]]

    if len(nameMatches) + len(idMatches) == 1:
        if len(nameMatches) == 1: return atlases[nameMatches[0]]
        else: return atlases[idMatches[0]]

    # If no exact match, test for a partial match
    nameMatches = [idOrName in n for n in allNames]
    idMatches = [idOrName in i for i in allIDs]

    nameMatches = [i for i in range(len(nameMatches)) if nameMatches[i]]
    idMatches = [i for i in range(len(idMatches)) if idMatches[i]]

    totalMatches = len(nameMatches) + len(idMatches)

    # No matches
    if totalMatches == 0:
        raise IdentifyError('Could not find any atlas '
                            'matching {}'.format(idOrName))

    # More than two matches, or a
    # different ID/name pair matched
    if totalMatches > 2 or (totalMatches == 2 and nameMatches != idMatches):

        possible = [allNames[m] for m in nameMatches] + \
                   [allIDs[  m] for m in idMatches]

        raise IdentifyError('{} matched multiple atlases! Could match one '
                            'of: {}'.format(idOrName, ', '.join(possible)))

    # Either one exact match to an ID or name,
    # or a match to an equivalent ID/name
    if len(nameMatches) == 1: return atlases[nameMatches[0]]
    else: return atlases[idMatches[0]]
示例#6
0
def test_dumpatlases():
    """Test the ohi --dumpatlases option. """

    capture = CaptureStdout()

    with capture:
        fslatlasq.main('ohi --dumpatlases'.split())

    atlases = fslatlases.listAtlases()
    atlases = [a.name for a in atlases]
    atlases = sorted(atlases)

    assert capture.stdout.strip() == '\n'.join(atlases)
示例#7
0
def Atlas(name):
    """
    Reads in the atlas from the FSL standard atlases

    :param name: name of the atlas
    :return: fsl.data.atlases.Atlas representation of an FSL atlas
    """
    atlases.rescanAtlases()
    if not atlases.hasAtlas(name):
        atlas_names = tuple(desc.atlasID for desc in atlases.listAtlases())
        raise argparse.ArgumentTypeError('Requested atlas %r not one of: %r' %
                                         (name, atlas_names))
    return atlases.loadAtlas(name)
示例#8
0
    def __buildAtlasList(self):
        """Clears and recreates the atlas list. Also clears all existing
        region lists.
        """

        atlasDescs = atlases.listAtlases()

        # This method is called whenever any
        # atlases are added/removed. We want
        # to preserve any region lists for
        # atlases that are still in the atlas
        # registry.
        regionLists = dict(self.__regionLists)

        # If a region list is currently
        # being shown, clear it.
        regionList = self.__regionSizer.GetItem(1).GetWindow()
        if regionList is not None:
            regionList.Show(False)
            self.__regionSizer.Remove(1)
            self.__regionSizer.AddStretchSpacer()

        self.__regionLists = {}

        # Now clear and re-populate the atlas list
        self.__atlasList.Clear()
        for i, atlasDesc in enumerate(atlasDescs):

            self.__atlasList.Append(atlasDesc.name, atlasDesc)
            self.__updateAtlasState(atlasDesc)

            widget = OverlayListWidget(self.__atlasList,
                                       atlasDesc.atlasID,
                                       self.__atlasPanel,
                                       self)

            self.__atlasList.SetItemWidget(i, widget)

        # Restore references to region lists
        # for atlases that still exist
        for atlasID, regionList in regionLists.items():
            if atlases.hasAtlas(atlasID):
                self.__regionLists[atlasID] = regionList
            else:
                regionList.Destroy()

        self.__regionSizer.Layout()
    def __onRegionFilter(self, ev):
        """Called when the user enters some text in the region filter.

        Filters the region list (see the :meth:`.EditableListBox.ApplyFilter`
        method), and updates all items in the atlas list (see the
        :meth:`__updateAtlasState` method).
        """

        filterStr = self.__regionFilter.GetValue().lower().strip()

        for atlasDesc in atlases.listAtlases():

            self.__updateAtlasState(atlasDesc)

            listBox = self.__regionLists.get(atlasDesc.atlasID, None)

            if listBox is not None:
                listBox.ApplyFilter(filterStr, ignoreCase=True)
示例#10
0
def test_bad_atlas():
    """Test the ohi -a "atlas" ..., with a non-existent atlas. """

    capture = CaptureStdout()

    atlases = fslatlases.listAtlases()
    atlases = sorted([a.name for a in atlases])

    expected = ['Invalid atlas name. Try one of:'] + atlases
    expected = '\n'.join(expected)

    cmds = ['ohi -a "non-existent atlas" -c "0,0,0"',
            'ohi -a "non-existent atlas" -m "nomask"']

    for cmd in cmds:
        capture.reset()
        with capture:
            fslatlasq.main(shlex.split(cmd))
            assert capture.stdout.strip() == expected
    def __init__(self, parent, overlayList, displayCtx, frame, atlasPanel):
        """Create an ``AtlasManagementPanel``.

        :arg parent:      the :mod:`wx` parent object.

        :arg overlayList: The :class:`.OverlayList` instance.

        :arg displayCtx:  The :class:`.DisplayContext` instance.

        :arg frame:       The :class:`.FSLeyesFrame` instance.

        :arg atlasPanel:  The :class:`.AtlasPanel` instance that has created
                          this ``AtlasManagementPanel``.
        """
        fslpanel.FSLeyesPanel.__init__(
            self, parent, overlayList, displayCtx, frame)

        descs = atlases.listAtlases()
        names = [d.name     for d in descs]
        paths = [d.specPath for d in descs]

        self.__atlasList = elistbox.EditableListBox(
            self,
            labels=names,
            clientData=descs,
            tooltips=paths,
            style=(elistbox.ELB_NO_MOVE |
                   elistbox.ELB_TOOLTIP_DOWN))

        self.__sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.__sizer.Add(self.__atlasList, flag=wx.EXPAND, proportion=1)

        self.SetSizer(self.__sizer)
        self.SetMinSize(self.__sizer.GetMinSize())

        self.__atlasList.Bind(elistbox.EVT_ELB_ADD_EVENT,
                              self.__onListAdd)
        self.__atlasList.Bind(elistbox.EVT_ELB_REMOVE_EVENT,
                              self.__onListRemove)

        atlases.registry.register(self.name, self.__atlasAdded,   'add')
        atlases.registry.register(self.name, self.__atlasRemoved, 'remove')
示例#12
0
def listAtlases(namespace):
    """List all available atlases. """
    atlases = fslatlases.listAtlases()

    if namespace.extended:
        for a in atlases:
            print('{} [{}]'.format(a.name, a.atlasID))
            print('  Spec:          {}'.format(a.specPath))
            print('  Type:          {}'.format(a.atlasType))
            print('  Labels:        {}'.format(len(a.labels)))
            for i in a.images:
                print('  Image:         {}'.format(i))
            for i in a.summaryImages:
                print('  Summary image: {}'.format(i))
            print()

    else:
        ids = [a.atlasID for a in atlases]
        names = [a.name for a in atlases]

        printColumns((ids, names), ('ID', 'Full name'))
示例#13
0
    def __buildAtlasList(self):
        """Clears and then builds the list of available atlases. The
        This is performed asynchronously, via the :func:`.idle.run` function,
        although the atlas list widget is updated on the ``wx`` idle loop.
        """

        # This method gets called whenever atlases
        # are added to/from the list.
        # We want to preserve the 'enabled' state of
        # any atlases that are still present in the
        # atlas registry.
        enabledAtlases = dict(self.__enabledAtlases)

        self.__enabledAtlases = {}

        self.__atlasList.Clear()

        atlasDescs = atlases.listAtlases()

        for i, atlasDesc in enumerate(atlasDescs):

            atlasID = atlasDesc.atlasID

            self.__atlasList.Append(atlasDesc.name, atlasID)

            enabled = atlasID in enabledAtlases
            widget = AtlasListWidget(self.__atlasList,
                                     i,
                                     self,
                                     atlasID,
                                     enabled=enabled)

            self.__atlasList.SetItemWidget(i, widget)

            if enabled:
                self.__enabledAtlases[atlasID] = enabledAtlases[atlasID]
示例#14
0
def test_coords(seed):
    """Test the ohi -a "atlas" -c "coords" mode. """
    def expectedProbOutput(atlas, coords):
        probs = atlas.values(coords)
        expected = '<b>{}</b><br>'.format(atlas.desc.name)
        nzprobs = []

        for i, p in enumerate(probs):
            if p > 0:
                label = atlas.desc.labels[i].name
                nzprobs.append((p, label))

        if len(nzprobs) > 0:
            nzprobs = reversed(sorted(nzprobs, key=lambda b: b[0]))
            nzprobs = [
                '{:d}% {}'.format(int(round(p)), l) for (p, l) in nzprobs
            ]
            expected += ', '.join(nzprobs)
        else:
            expected += 'No label found!'

        return expected

    def expectedLabelOutput(atlas, coords):
        label = atlas.label(coords)
        expected = '<b>{}</b><br>'.format(atlas.desc.name)

        if label is None:
            return expected + 'Unclassified'
        else:
            return expected + atlas.desc.find(value=int(label)).name

    capture = CaptureStdout()

    # random coordinates in MNI152 space,
    # with some coordinates out of bounds
    ncoords = 50
    xc = -100 + 190 * np.random.random(ncoords)
    yc = -130 + 220 * np.random.random(ncoords)
    zc = -80 + 120 * np.random.random(ncoords)
    coords = np.vstack((xc, yc, zc)).T

    fslatlases.rescanAtlases()
    atlases = fslatlases.listAtlases()

    for ad in atlases:

        # atlasquery/ohi always uses 2mm resolution
        atlas = fslatlases.loadAtlas(ad.atlasID, resolution=2)

        print(ad.name)

        for x, y, z in coords:

            cmd = 'ohi -a "{}" -c "{},{},{}"'.format(ad.name, x, y, z)

            capture.reset()
            with capture:
                fslatlasq.main(shlex.split(cmd))

            if isinstance(atlas, fslatlases.ProbabilisticAtlas):
                expected = expectedProbOutput(atlas, (x, y, z))

            # LabelAtlas
            else:
                expected = expectedLabelOutput(atlas, (x, y, z))

            assert capture.stdout.strip() == expected.strip()
示例#15
0
def ohi(namespace):
    """Emulates the FSL ``atlasquery`` tool."""

    atlasDesc = None

    def dumpatlases():
        atlases = [a.name for a in fslatlases.listAtlases()]
        print('\n'.join(sorted(atlases)))

    if namespace.dumpatlases:
        dumpatlases()
        return

    for a in fslatlases.listAtlases():
        if a.name == namespace.atlas:
            atlasDesc = a
            break

    if atlasDesc is None:
        print('Invalid atlas name. Try one of:')
        dumpatlases()
        return

    # Mask query.
    if namespace.ohiMask is not None:

        # atlasquery always uses 2mm atlas versions
        mask = fslimage.Image(namespace.ohiMask)
        labels, props = maskQuery(atlasDesc, [mask], resolution=2)
        labels = labels[0]
        props = props[0]

        for lbl, prop in zip(labels, props):
            lbl = atlasDesc.labels[int(lbl)].name
            print('{}:{:0.4f}'.format(lbl, prop))

    # Coordinate query
    else:
        coord = namespace.coord.strip('"')
        coord = [float(c) for c in coord.split(',')]
        labels, props = coordQuery(atlasDesc, [coord], False, resolution=2)

        labels = labels[0]
        props = props[0]

        if atlasDesc.atlasType == 'label':

            labels = labels[0]

            if labels is None: label = 'Unclassified'
            else: label = atlasDesc.labels[int(labels)].name
            print('<b>{}</b><br>{}'.format(atlasDesc.name, label))

        elif atlasDesc.atlasType == 'probabilistic':

            labelStrs = []

            if len(labels) > 0:
                props, labels = zip(*reversed(sorted(zip(props, labels))))

            for label, prop in zip(labels, props):
                label = atlasDesc.labels[int(label)].name
                labelStrs.append('{:d}% {}'.format(int(round(prop)), label))

            if len(labelStrs) == 0: labels = 'No label found!'
            else: labels = ', '.join(labelStrs)

            print('<b>{}</b><br>{}'.format(atlasDesc.name, labels))
示例#16
0
def test_mask(seed):
    """Test the ohi -a "atlas" -m "mask" mode, with label and probabilistic
    atlases.
    """
    def expectedLabelOutput(mask, atlas):

        labels, props = atlas.maskLabel(mask)
        exp = []

        for lbl, prop in zip(labels, props):
            name = desc.find(value=int(lbl)).name
            exp.append('{}:{:0.4f}'.format(name, prop))

        return '\n'.join(exp)

    def expectedProbOutput(mask, atlas):

        props = atlas.maskValues(mask)
        labels = [l.index for l in atlas.desc.labels]
        exp = []

        for lbl, prop in zip(labels, props):
            if prop > 0:
                exp.append('{}:{:0.4f}'.format(desc.labels[int(lbl)].name,
                                               prop))

        return '\n'.join(exp)

    fslatlases.rescanAtlases()

    capture = CaptureStdout()
    atlases = fslatlases.listAtlases()

    with tempdir() as td:

        maskfile = op.join(td, 'mask.nii')

        for desc in atlases:

            # atlasquery always uses 2mm
            # resolution versions of atlases
            atlas2mm = fslatlases.loadAtlas(desc.atlasID, resolution=2)

            # Test with 1mm and 2mm masks
            for res in [1, 2]:
                atlasimg = fslatlases.loadAtlas(desc.atlasID, resolution=res)
                maskimg = make_random_mask(maskfile, atlasimg.shape[:3],
                                           atlasimg.voxToWorldMat)

                cmd = 'ohi -a "{}" -m {}'.format(desc.name, maskfile)
                print(cmd)

                capture.reset()
                with capture:
                    fslatlasq.main(shlex.split(cmd))

                if isinstance(atlasimg, fslatlases.LabelAtlas):
                    expected = expectedLabelOutput(maskimg, atlas2mm)
                elif isinstance(atlasimg, fslatlases.ProbabilisticAtlas):
                    expected = expectedProbOutput(maskimg, atlas2mm)

                assert capture.stdout.strip() == expected
示例#17
0
 def dumpatlases():
     atlases = [a.name for a in fslatlases.listAtlases()]
     print('\n'.join(sorted(atlases)))