Skip to content
Snippets Groups Projects
Commit 2adb5711 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Image uses a SafeIndexedGzipFile for indexed images. ImageWrapper can

optionally be told to calculate data ranges on a separate thread.
parent cfac8139
No related branches found
No related tags found
No related merge requests found
...@@ -370,7 +370,8 @@ class Image(Nifti1, notifier.Notifier): ...@@ -370,7 +370,8 @@ class Image(Nifti1, notifier.Notifier):
xform=None, xform=None,
loadData=True, loadData=True,
calcRange=True, calcRange=True,
indexed=False): indexed=False,
threaded=False):
"""Create an ``Image`` object with the given image data or file name. """Create an ``Image`` object with the given image data or file name.
:arg image: A string containing the name of an image file to load, :arg image: A string containing the name of an image file to load,
...@@ -406,6 +407,11 @@ class Image(Nifti1, notifier.Notifier): ...@@ -406,6 +407,11 @@ class Image(Nifti1, notifier.Notifier):
:arg indexed: If ``True``, and the file is gzipped, it is opened :arg indexed: If ``True``, and the file is gzipped, it is opened
using the :mod:`indexed_gzip` package. Otherwise the using the :mod:`indexed_gzip` package. Otherwise the
file is opened by ``nibabel``. file is opened by ``nibabel``.
:arg threaded: If ``True``, the :class:`.ImageWrapper` will use a
separate thread for data range calculation. Defaults
to ``False``.
""" """
import nibabel as nib import nibabel as nib
...@@ -480,7 +486,8 @@ class Image(Nifti1, notifier.Notifier): ...@@ -480,7 +486,8 @@ class Image(Nifti1, notifier.Notifier):
self.__suppressDataRange = False self.__suppressDataRange = False
self.__imageWrapper = imagewrapper.ImageWrapper(self.nibImage, self.__imageWrapper = imagewrapper.ImageWrapper(self.nibImage,
self.name, self.name,
loadData=loadData) loadData=loadData,
threaded=threaded)
if calcRange: if calcRange:
self.calcRange() self.calcRange()
...@@ -510,7 +517,11 @@ class Image(Nifti1, notifier.Notifier): ...@@ -510,7 +517,11 @@ class Image(Nifti1, notifier.Notifier):
def __del__(self): def __del__(self):
"""Closes any open file handles. """ """Closes any open file handles, and clears some references. """
self.__nibImage = None
self.__imageWrapper = None
if self.__fileobj is not None: if self.__fileobj is not None:
self.__fileobj.close() self.__fileobj.close()
...@@ -805,7 +816,7 @@ def loadIndexedImageFile(filename): ...@@ -805,7 +816,7 @@ def loadIndexedImageFile(filename):
log.debug('Loading {} using indexed gzip'.format(filename)) log.debug('Loading {} using indexed gzip'.format(filename))
fobj = igzip.IndexedGzipFile( fobj = igzip.SafeIndexedGzipFile(
filename=filename, filename=filename,
spacing=4194304, spacing=4194304,
readbuf_size=131072) readbuf_size=131072)
......
...@@ -41,6 +41,7 @@ import numpy as np ...@@ -41,6 +41,7 @@ import numpy as np
import nibabel as nib import nibabel as nib
import fsl.utils.notifier as notifier import fsl.utils.notifier as notifier
import fsl.utils.async as async
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -121,7 +122,12 @@ class ImageWrapper(notifier.Notifier): ...@@ -121,7 +122,12 @@ class ImageWrapper(notifier.Notifier):
""" """
def __init__(self, image, name=None, loadData=False, dataRange=None): def __init__(self,
image,
name=None,
loadData=False,
dataRange=None,
threaded=False):
"""Create an ``ImageWrapper``. """Create an ``ImageWrapper``.
:arg image: A ``nibabel.Nifti1Image``. :arg image: A ``nibabel.Nifti1Image``.
...@@ -137,6 +143,10 @@ class ImageWrapper(notifier.Notifier): ...@@ -137,6 +143,10 @@ class ImageWrapper(notifier.Notifier):
:arg dataRange: A tuple containing the initial ``(min, max)`` data :arg dataRange: A tuple containing the initial ``(min, max)`` data
range to use. See the :meth:`reset` method for range to use. See the :meth:`reset` method for
important information about this parameter. important information about this parameter.
:arg threaded: If ``True``, the data range is updated on a
:class:`.TaskThread`. Otherwise (the default), the
data range is updated directly on reads/writes.
""" """
self.__image = image self.__image = image
...@@ -167,6 +177,22 @@ class ImageWrapper(notifier.Notifier): ...@@ -167,6 +177,22 @@ class ImageWrapper(notifier.Notifier):
if loadData: if loadData:
self.loadData() self.loadData()
if not threaded:
self.__taskThread = None
else:
self.__taskThread = async.TaskThread()
self.__taskThread.start()
def __del__(self):
"""If this ``ImageWrapper`` was created with ``threaded=True``,
the :class:`.TaskThread` is stopped.
"""
self.__image = None
if self.__taskThread is not None:
self.__taskThread.stop()
self.__taskThraed = None
def reset(self, dataRange=None): def reset(self, dataRange=None):
"""Reset the internal state and known data range of this """Reset the internal state and known data range of this
...@@ -426,7 +452,12 @@ class ImageWrapper(notifier.Notifier): ...@@ -426,7 +452,12 @@ class ImageWrapper(notifier.Notifier):
# the provided data to avoid # the provided data to avoid
# reading it in again. # reading it in again.
self.__expandCoverage(slices) if self.__taskThread is None:
self.__expandCoverage(slices)
else:
name = '{}_read_{}'.format(id(self), slices)
if not self.__taskThread.isQueued(name):
self.__taskThread.enqueue(name, self.__expandCoverage, slices)
def __updateDataRangeOnWrite(self, slices, data): def __updateDataRangeOnWrite(self, slices, data):
...@@ -476,7 +507,13 @@ class ImageWrapper(notifier.Notifier): ...@@ -476,7 +507,13 @@ class ImageWrapper(notifier.Notifier):
self.__coverage[:, :, vol] = np.nan self.__coverage[:, :, vol] = np.nan
self.__volRanges[ vol, :] = np.nan self.__volRanges[ vol, :] = np.nan
self.__expandCoverage(slices)
if self.__taskThread is None:
self.__expandCoverage(slices)
else:
name = '{}_write_{}'.format(id(self), slices)
if not self.__taskThread.isQueued(name):
self.__taskThread.enqueue(name, self.__expandCoverage, slices)
def __getitem__(self, sliceobj): def __getitem__(self, sliceobj):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment