def set_data(self, dat, casting='unsafe'): if '+' not in self.mode: raise RuntimeError('Cannot write into read-only volume. ' 'Re-map in mode "r+" to allow in-place ' 'writing.') # --- convert to numpy --- if torch.is_tensor(dat): dat = dat.detach().cpu() dat = np.asanyarray(dat) # --- sanity check --- if dat.shape != self.shape: raise ValueError( 'Expected an array of shape {} but got {}.'.format( self.shape, dat.shape)) # --- special case if empty view --- if dat.size == 0: # nothing to write return self # --- cast --- dat = volutils.cast(dat, self.dtype, casting) # --- unpermute --- drop, perm, slicer = split_operation(self.permutation, self.slicer, 'w') dat = dat[drop].transpose(perm) # --- dispatch --- if self.is_compressed('image'): if not all(is_fullslice(slicer, self._shape)): # read-and-write slice = dat with self.fileobj('image', 'r') as f: dat = self._read_data_raw(fileobj=f, mmap=False) dat[slicer] = slice with self.fileobj('image', 'w', seek=0) as f: if self.same_file('image', 'header'): self._set_header_raw(fileobj=f) self._write_data_raw_full(dat, fileobj=f) if self.same_file('image', 'footer'): self._set_footer_raw(fileobj=f) elif all(is_fullslice(slicer, self._shape)): with self.fileobj('image', 'r+') as f: self._write_data_raw_full(dat, fileobj=f) else: with self.fileobj('image', 'r+') as f: self._write_data_raw_partial(dat, slicer, fileobj=f) return self
def _read_data_raw(self, slicer=None, tiffobj=None): """Read native data Dispatch to `_read_data_raw_full` or `_read_data_raw_partial`. Parameters ---------- slicer : tuple[index_like], optional A tuple of indices that describe the chunk of data to read. If None, read everything. tiffobj : file object, default=`self.fileobj('image', 'r')` A file object (with `seek`, `read`) from which to read Returns ------- dat : np.ndarray """ if tiffobj is None: with self.tiffobj() as tiffobj: return self._read_data_raw(slicer, tiffobj) # load sub-array if slicer is None or all(is_fullslice(slicer, self._shape)): dat = self._read_data_raw_full(tiffobj) else: dat = self._read_data_raw_partial(slicer, tiffobj) return dat
def _read_data_raw(self, slicer=None, fileobj=None, mmap=None): """Read native data Dispatch to `_read_data_raw_full` or `_read_data_raw_partial`. Parameters ---------- slicer : tuple[index_like], optional A tuple of indices that describe the chunk of data to read. If None, read everything. fileobj : file object, default=`self.fileobj('image', 'r')` A file object (with `seek`, `read`) from which to read mmap : bool, default=`self._image.dataobj.mmap` If True, try to memory map the data. Returns ------- dat : np.ndarray """ # load sub-array if slicer is None or all(is_fullslice(slicer, self._shape)): dat = self._read_data_raw_full(fileobj, mmap=mmap) if slicer is not None: dat = dat[slicer] else: dat = self._read_data_raw_partial(slicer, fileobj) return dat
def _write_data_raw_partial(self, dat, slicer, fileobj=None): """Write native data Parameters ---------- dat : np.ndarray Should already have the on-disk data type, including byte-order slicer : tuple[index_like] Unpermuted slicer, without new axes. fileobj : nibabel.Opener, optional File object """ if fileobj is None: # Create our own context with self.fileobj('image', 'r+') as fileobj: return self._write_data_raw_partial(dat, slicer, fileobj) # sanity checks for developers # (asserts because proper conversion/dispatch should happen before) assert isinstance(dat, np.ndarray), "Data should already be numpy" assert dat.dtype == self.dtype, "Data should already have correct type" assert not self.is_compressed('image'), "Data cannot be compressed" assert not all(is_fullslice( slicer, self._shape)), "No need for partial writing" if not fileobj.readable(): raise RuntimeError('File object not readable') if not fileobj.writable(): raise RuntimeError('File object not writable') # write data chunk writeslice(dat, fileobj, tuple(slicer), self._shape, self.dtype, offset=self._image.dataobj.offset, order=self._image.dataobj.order, lock=self._lock['image'])
def level(self, val): if val != self.level and not all(is_fullslice(self.slicer)): raise RuntimeError("Cannot change resolution level in a view") self._level = val self._cache = {}
def series(self, val): if val != self.series and not all(is_fullslice(self.slicer)): raise RuntimeError("Cannot change series in a view") self._series = val self._cache = {}