diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 63d17059ddb8552813c9a62504aa555b385a692b..56ce3f6b90c9afe77eabd6b0ea60d5cfad824f5f 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,8 +2,8 @@ This document contains the ``fslpy`` release history in reverse chronological
 order.
 
 
-3.7.0 (Under development)
--------------------------
+3.7.0 (Friday 20th August 2021)
+-------------------------------
 
 
 Added
@@ -17,6 +17,10 @@ Added
 Changed
 ^^^^^^^
 
+
+* Performance of the :mod:`.imglob`, :mod:`.imln`, :mod:`imtest`, :mod:`.imrm`
+  and :mod:`.remove_ext` scripts has been improved, by re-organising them to
+  avoid unnecessary and expensive imports such as ``numpy``.
 * The default behaviour of the :func:`fsl.utils.run.run` function (and hence
   that of all :mod:`fsl.wrappers` functions) has been changed so that the
   standard output and error of the called command is now forwarded to the
diff --git a/fsl/scripts/imglob.py b/fsl/scripts/imglob.py
index 1e756dee6f79d5e3f4a5f087ba355c5a795771bd..87314e8fb65eab271ac10a4dd3fe206f016e034c 100644
--- a/fsl/scripts/imglob.py
+++ b/fsl/scripts/imglob.py
@@ -10,14 +10,9 @@ NIFTI/ANALYZE image files.
 
 
 import                   sys
-import                   warnings
+import                   glob
 import fsl.utils.path as fslpath
 
-# See atlasq.py for explanation
-with warnings.catch_warnings():
-    warnings.filterwarnings("ignore", category=FutureWarning)
-    import fsl.data.image as fslimage
-
 
 usage = """
 Usage: imglob [-extension/extensions] <list of names>
@@ -25,8 +20,17 @@ Usage: imglob [-extension/extensions] <list of names>
        -extensions for image list with full extensions
 """.strip()
 
-exts   = fslimage.ALLOWED_EXTENSIONS
-groups = fslimage.FILE_GROUPS
+
+# The lists below are defined in the
+# fsl.data.image class, but are duplicated
+# here for performance (to avoid import of
+# nibabel/numpy/etc).
+exts   = ['.nii.gz', '.nii', '.img', '.hdr', '.img.gz', '.hdr.gz']
+"""List of supported image file extensions. """
+
+
+groups = [('.hdr', '.img'), ('.hdr.gz', '.img.gz')]
+"""List of known image file groups (image/header file pairs). """
 
 
 def imglob(paths, output=None):
@@ -59,12 +63,27 @@ def imglob(paths, output=None):
 
     imgfiles = []
 
+    # Expand any wildcard paths if provided.
+    # Depending on the way that imglob is
+    # invoked, this may not get done by the
+    # calling shell.
+    expanded = []
+    for path in paths:
+        if any(c in path for c in '*?[]'):
+            expanded.extend(glob.glob(path))
+        else:
+            expanded.append(path)
+
+    paths = expanded
+
     # Build a list of all image files (both
     # hdr and img and otherwise) that match
     for path in paths:
         try:
-            path = fslimage.removeExt(path)
-            imgfiles.extend(fslimage.addExt(path, unambiguous=False))
+            path = fslpath.removeExt(path, allowedExts=exts)
+            imgfiles.extend(fslpath.addExt(path,
+                                           allowedExts=exts,
+                                           unambiguous=False))
         except fslpath.PathError:
             continue
 
diff --git a/fsl/scripts/imln.py b/fsl/scripts/imln.py
index 88955f3cb36300853f58f276f6e4dedb6ffda18e..74bcaf395cfc46f20fac9e8fcbca74eb306b3cf0 100644
--- a/fsl/scripts/imln.py
+++ b/fsl/scripts/imln.py
@@ -17,19 +17,22 @@ to NIFTI image files.
 import os.path        as op
 import                   os
 import                   sys
-import                   warnings
-
 import fsl.utils.path as fslpath
 
 
-# See atlasq.py for explanation
-with warnings.catch_warnings():
-    warnings.filterwarnings("ignore", category=FutureWarning)
-    import fsl.data.image as fslimage
-
+# The lists below are defined in the
+# fsl.data.image class, but are duplicated
+# here for performance (to avoid import of
+# nibabel/numpy/etc).
+exts = ['.nii.gz', '.nii',
+        '.img',    '.hdr',
+        '.img.gz', '.hdr.gz',
+        '.mnc',    '.mnc.gz']
+"""List of file extensions that are supported by ``imtest``.
+"""
 
-ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
-"""List of file extensions that are supported by ``imln``. """
+groups = [('.hdr', '.img'), ('.hdr.gz', '.img.gz')]
+"""List of known image file groups (image/header file pairs). """
 
 
 usage = """
@@ -50,8 +53,8 @@ def main(argv=None):
         return 1
 
     target, linkbase = argv
-    target           = fslpath.removeExt(target,   ALLOWED_EXTENSIONS)
-    linkbase         = fslpath.removeExt(linkbase, ALLOWED_EXTENSIONS)
+    target           = fslpath.removeExt(target,   exts)
+    linkbase         = fslpath.removeExt(linkbase, exts)
 
     # Target must exist, so we can
     # infer the correct extension(s).
@@ -59,8 +62,8 @@ def main(argv=None):
     # (e.g. a.img without a.hdr).
     try:
         targets = fslpath.getFileGroup(target,
-                                       allowedExts=ALLOWED_EXTENSIONS,
-                                       fileGroups=fslimage.FILE_GROUPS,
+                                       allowedExts=exts,
+                                       fileGroups=groups,
                                        unambiguous=True)
     except Exception as e:
         print(f'Error: {e}')
@@ -70,7 +73,7 @@ def main(argv=None):
         if not op.exists(target):
             continue
 
-        ext  = fslpath.getExt(target, ALLOWED_EXTENSIONS)
+        ext  = fslpath.getExt(target, exts)
         link = f'{linkbase}{ext}'
 
         try:
diff --git a/fsl/scripts/imrm.py b/fsl/scripts/imrm.py
index bd81103325b6d8dea25f0b88f02c3bbb40555f6c..7d8287b6e937c55f2e95a6f287d3c597c22abf97 100644
--- a/fsl/scripts/imrm.py
+++ b/fsl/scripts/imrm.py
@@ -13,22 +13,22 @@ import itertools      as it
 import os.path        as op
 import                   os
 import                   sys
-import                   warnings
-
 import fsl.utils.path as fslpath
 
-# See atlasq.py for explanation
-with warnings.catch_warnings():
-    warnings.filterwarnings("ignore", category=FutureWarning)
-    import fsl.data.image as fslimage
-
 
 usage = """Usage: imrm <list of image names to remove>
 NB: filenames can be basenames or not
 """.strip()
 
 
-ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
+# This list is defined in the
+# fsl.data.image class, but are duplicated
+# here for performance (to avoid import of
+# nibabel/numpy/etc).
+exts = ['.nii.gz', '.nii',
+        '.img',    '.hdr',
+        '.img.gz', '.hdr.gz',
+        '.mnc',    '.mnc.gz']
 """List of file extensions that are removed by ``imrm``. """
 
 
@@ -42,9 +42,9 @@ def main(argv=None):
         print(usage)
         return 1
 
-    prefixes = [fslpath.removeExt(p, ALLOWED_EXTENSIONS) for p in argv]
+    prefixes = [fslpath.removeExt(p, exts) for p in argv]
 
-    for prefix, ext in it.product(prefixes, ALLOWED_EXTENSIONS):
+    for prefix, ext in it.product(prefixes, exts):
 
         path = f'{prefix}{ext}'
 
diff --git a/fsl/scripts/imtest.py b/fsl/scripts/imtest.py
index f03c28442b52ed79f535b12aae444e310cf83bc3..b0fed7c275e547b18e048397c2601f8292cfcc30 100644
--- a/fsl/scripts/imtest.py
+++ b/fsl/scripts/imtest.py
@@ -11,18 +11,22 @@ not, without having to know the file suffix (.nii, .nii.gz, etc).
 
 import os.path        as op
 import                   sys
-import                   warnings
-
 import fsl.utils.path as fslpath
 
-# See atlasq.py for explanation
-with warnings.catch_warnings():
-    warnings.filterwarnings("ignore", category=FutureWarning)
-    import fsl.data.image as fslimage
 
+# The lists below are defined in the
+# fsl.data.image class, but are duplicated
+# here for performance (to avoid import of
+# nibabel/numpy/etc).
+exts = ['.nii.gz', '.nii',
+        '.img',    '.hdr',
+        '.img.gz', '.hdr.gz',
+        '.mnc',    '.mnc.gz']
+"""List of file extensions that are supported by ``imtest``.
+"""
 
-ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
-"""List of file extensions that are supported by ``imln``. """
+groups = [('.hdr', '.img'), ('.hdr.gz', '.img.gz')]
+"""List of known image file groups (image/header file pairs). """
 
 
 def main(argv=None):
@@ -38,7 +42,7 @@ def main(argv=None):
         print('0')
         return 0
 
-    path = fslpath.removeExt(argv[0], ALLOWED_EXTENSIONS)
+    path = fslpath.removeExt(argv[0], exts)
     path = op.realpath(path)
 
     # getFileGroup will raise an error
@@ -47,8 +51,8 @@ def main(argv=None):
     # image) does not exist
     try:
         fslpath.getFileGroup(path,
-                             allowedExts=ALLOWED_EXTENSIONS,
-                             fileGroups=fslimage.FILE_GROUPS,
+                             allowedExts=exts,
+                             fileGroups=groups,
                              unambiguous=True)
         print('1')
     except fslpath.PathError:
diff --git a/fsl/scripts/remove_ext.py b/fsl/scripts/remove_ext.py
index fc21094ff113576cc808f25fc3dbde1b7f38ff4f..54e62f5732681fd32d33926b2561cf3e4d092af5 100644
--- a/fsl/scripts/remove_ext.py
+++ b/fsl/scripts/remove_ext.py
@@ -6,22 +6,22 @@
 #
 
 
-import sys
-import warnings
-
+import                   sys
 import fsl.utils.path as fslpath
 
-# See atlasq.py for explanation
-with warnings.catch_warnings():
-    warnings.filterwarnings("ignore", category=FutureWarning)
-    import fsl.data.image as fslimage
-
 
 usage = """Usage: remove_ext <list of image paths to remove extension from>
 """.strip()
 
 
-ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
+# This list is defined in the
+# fsl.data.image class, but are duplicated
+# here for performance (to avoid import of
+# nibabel/numpy/etc).
+exts = ['.nii.gz', '.nii',
+        '.img',    '.hdr',
+        '.img.gz', '.hdr.gz',
+        '.mnc',    '.mnc.gz']
 """List of file extensions that are removed by ``remove_ext``. """
 
 
@@ -40,7 +40,7 @@ def main(argv=None):
     removed = []
 
     for path in argv:
-        removed.append(fslpath.removeExt(path, ALLOWED_EXTENSIONS))
+        removed.append(fslpath.removeExt(path, exts))
 
     print(' '.join(removed))
 
diff --git a/fsl/utils/path.py b/fsl/utils/path.py
index 09546f4b2cdf2660e234e49a7b09814232fac83e..bbaaa206f8c995181b139b3d668e0d201d331964 100644
--- a/fsl/utils/path.py
+++ b/fsl/utils/path.py
@@ -37,8 +37,6 @@ import            re
 
 from typing import Sequence, Tuple, Union
 
-from fsl.utils.platform import platform
-
 
 PathLike = Union[str, pathlib.Path]
 
@@ -596,6 +594,7 @@ def winpath(path):
     This requires WSL2 which supports the ``\\wsl$\\`` network path.
     wslpath is assumed to be an absolute path.
     """
+    from fsl.utils.platform import platform  # pylint: disable=import-outside-toplevel  # noqa: E501
     if not platform.fslwsl:
         return path
     else:
diff --git a/fsl/utils/platform.py b/fsl/utils/platform.py
index 1a49221ad455cfbfe2dace57d483010c2e89f019..3620ef9ade1b8dd8f90da0cb3225a87514e75c17 100644
--- a/fsl/utils/platform.py
+++ b/fsl/utils/platform.py
@@ -111,26 +111,15 @@ class Platform(notifier.Notifier):
         self.WX_MAC_CARBON = WX_MAC_CARBON
         self.WX_GTK        = WX_GTK
 
-        self.__inSSHSession = False
-        self.__inVNCSession = False
+        # initialise fsldir - see fsldir.setter
+        self.fsldir = self.fsldir
+
+        # These are all initialised on first access
         self.__glVersion    = None
         self.__glRenderer   = None
         self.__glIsSoftware = None
         self.__fslVersion   = None
-
-        # initialise fsldir - see fsldir.setter
-        self.fsldir = self.fsldir
-
-        # Determine if a display is available. We do
-        # this once at init (instead of on-demand in
-        # the canHaveGui method) because calling the
-        # IsDisplayAvailable function will cause the
-        # application to steal focus under OSX!
-        try:
-            import wx
-            self.__canHaveGui = wx.App.IsDisplayAvailable()
-        except ImportError:
-            self.__canHaveGui = False
+        self.__canHaveGui   = None
 
         # If one of the SSH_/VNC environment
         # variables is set, then we're probably
@@ -177,7 +166,7 @@ class Platform(notifier.Notifier):
         the event loop is called periodically, and so is not always running.
         """
         try:
-            import wx
+            import wx  # pylint: disable=import-outside-toplevel
             app = wx.GetApp()
 
             # TODO Previously this conditional
@@ -216,6 +205,17 @@ class Platform(notifier.Notifier):
         'Equivalent functionality is available in fsleyes-widgets.')
     def canHaveGui(self):
         """``True`` if it is possible to create a GUI, ``False`` otherwise. """
+
+        # Determine if a display is available. Note that
+        # calling the IsDisplayAvailable function will
+        # cause the application to steal focus under OSX!
+        if self.__canHaveGui is None:
+            try:
+                import wx  # pylint: disable=import-outside-toplevel
+                self.__canHaveGui = wx.App.IsDisplayAvailable()
+            except ImportError:
+                self.__canHaveGui = False
+
         return self.__canHaveGui
 
 
@@ -261,14 +261,14 @@ class Platform(notifier.Notifier):
         if not self.canHaveGui:
             return WX_UNKNOWN
 
-        import wx
+        import wx  # pylint: disable=import-outside-toplevel
 
         pi = [t.lower() for t in wx.PlatformInfo]
 
-        if   any(['cocoa'  in p for p in pi]): plat = WX_MAC_COCOA
-        elif any(['carbon' in p for p in pi]): plat = WX_MAC_CARBON
-        elif any(['gtk'    in p for p in pi]): plat = WX_GTK
-        else:                                  plat = WX_UNKNOWN
+        if   any('cocoa'  in p for p in pi): plat = WX_MAC_COCOA
+        elif any('carbon' in p for p in pi): plat = WX_MAC_CARBON
+        elif any('gtk'    in p for p in pi): plat = WX_GTK
+        else:                                plat = WX_UNKNOWN
 
         if plat is WX_UNKNOWN:
             log.warning('Could not determine wx platform from '
@@ -290,7 +290,7 @@ class Platform(notifier.Notifier):
         if not self.canHaveGui:
             return WX_UNKNOWN
 
-        import wx
+        import wx  # pylint: disable=import-outside-toplevel
 
         pi        = [t.lower() for t in wx.PlatformInfo]
         isPhoenix = False
@@ -323,7 +323,9 @@ class Platform(notifier.Notifier):
 
     @property
     def fslwsl(self):
-        """Boolean flag indicating whether FSL is installed in Windows Subsystem for Linux """
+        """Boolean flag indicating whether FSL is installed in Windows
+        Subsystem for Linux
+        """
         return self.fsldir is not None and self.fsldir.startswith("\\\\wsl$")
 
 
@@ -352,8 +354,9 @@ class Platform(notifier.Notifier):
             if op.exists(versionFile):
                 with open(versionFile, 'rt') as f:
                     # split string at colon for new hash style versions
-                    # first object in list is the non-hashed version string (e.g. 6.0.2)
-                    # if no ":hash:" then standard FSL version string is still returned
+                    # first object in list is the non-hashed version string
+                    # (e.g. 6.0.2) if no ":hash:" then standard FSL version
+                    # string is still returned
                     self.__fslVersion = f.read().strip().split(":")[0]
 
         self.notify(value=value)
diff --git a/fsl/version.py b/fsl/version.py
index ca8bdbc31a907847967a09a4498143f6caaeb049..9030805603613b6397c11d7fce25d31341d03a42 100644
--- a/fsl/version.py
+++ b/fsl/version.py
@@ -47,7 +47,7 @@ import            re
 import            string
 
 
-__version__ = '3.7.0.dev0'
+__version__ = '3.8.0.dev0'
 """Current version number, as a string. """
 
 
diff --git a/tests/test_scripts/test_imglob.py b/tests/test_scripts/test_imglob.py
index 5ce2c2bc517dfcc00fa5c4be69886fd360de570e..d1b261544990bc37cbb7ab6bd4f0754113ff57f4 100644
--- a/tests/test_scripts/test_imglob.py
+++ b/tests/test_scripts/test_imglob.py
@@ -100,6 +100,9 @@ def test_imglob_shouldPass2():
         ('file1.hdr file1.img file2.nii', 'file1 file2', 'primary', 'file1.hdr file2.nii'),
         ('file1.hdr file1.img file2.nii', 'file1 file2', 'all',     'file1.hdr file1.img file2.nii'),
 
+        # muiltiple files, given wildcard
+        ('file1.nii file2.nii', 'file*', 'prefix',  'file1 file2'),
+
         # no file
         ('file.nii', 'bag', 'prefix',  ''),
         ('file.nii', 'bag', 'primary', ''),