def _get_img2d(self, i, img, max_intens=0): """Get the 2D image from the given 3D image, scaling and downsampling as necessary. Args: i (int): Index of 3D image in sequence of 3D images, assuming order of ``(main_image, labels_img, borders_img)``. img (:obj:`np.ndarray`): 3D image from which to extract a 2D plane. max_intens (int): Number of planes to incorporate for maximum intensity projection; defaults to 0 to not perform this projection. Returns: :obj:`np.ndarray`: 2D plane, downsampled if necessary. """ z = self.coord[0] z_scale = 1 if self._img3d_scales[i] is not None: # rescale z-coordinate based on image scaling to the main image z_scale = self._img3d_scales[i][0] z = int(z * z_scale) # downsample to reduce access time; use same factor for both x and y # to retain aspect ratio downsample = self._downsample[i] img = img[:, ::downsample, ::downsample] if max_intens: # max intensity projection (MIP) across the given number of # planes available z_stop = z + int(max_intens * z_scale) num_z = len(img) if z_stop > num_z: z_stop = num_z z_range = np.arange(z, z_stop) img2d = plot_support.extract_planes(img[None], z_range, max_intens_proj=True)[0] else: img2d = img[z] return img2d
def setup_stack( image5d: np.ndarray, path: Optional[str] = None, offset: Optional[Sequence[int]] = None, roi_size: Optional[Sequence[int]] = None, slice_vals: Optional[Sequence[int]] = None, rescale: Optional[float] = None, labels_imgs: Optional[Sequence[np.ndarray]] = None) -> StackPlaneIO: """Set up a stack of images for export to file. Supports a stack of image files in a directory or a single volumetric image and associated labels images. Args: image5d: Images as a 4/5D Numpy array (t,z,y,x[c]). Can be None if ``path`` is set. path: Path to an image directory from which all files will be imported in Python sorted order, taking precedence over ``imaged5d``; defaults to None. offset: Tuple of offset given in user order (x, y, z); defaults to None. Requires ``roi_size`` to not be None. roi_size: Size of the region of interest in user order (x, y, z); defaults to None. Requires ``offset`` to not be None. slice_vals: List from which to construct a slice object to extract only a portion of the image. Defaults to None, which will give the whole image. If ``offset`` and ``roi_size`` are also given, ``slice_vals`` will only be used for its interval term. rescale: Rescaling factor for each image, performed on a plane-by-plane basis; defaults to None, in which case 1.0 will be used. labels_imgs: Sequence of labels-based images as a Numpy z,y,x arrays, typically including labels and borders images; defaults to None. Returns: Stack builder instance. """ print("Starting image stack setup") # build "z" slice, which will be applied to the transposed image interval = 1 # default to export each plane if offset is not None and roi_size is not None: # extract planes based on ROI settings # transpose coordinates to given plane _, arrs_1d = plot_support.transpose_images( config.plane, arrs_1d=[offset[::-1], roi_size[::-1]]) offset = arrs_1d[0][::-1] roi_size = arrs_1d[1][::-1] # ROI offset and size take precedence over slice vals except # for use of the interval term if slice_vals is not None and len(slice_vals) > 2: interval = slice_vals[2] size = roi_size[2] img_sl = slice(offset[2], offset[2] + size, interval) if interval is not None and interval < 0: # reverse start/stop order to iterate backward img_sl = slice(img_sl.stop, img_sl.start, interval) print("using ROI offset {}, size {}, {}".format(offset, size, img_sl)) elif slice_vals: # build directly from slice vals, replacing start and step if None sl = slice(*slice_vals) sl = [sl.start, sl.stop, sl.step] if sl[0] is None: # default to start at beginning of stack sl[0] = 0 if sl[2] is None: # default to interval/step of 1 sl[2] = 1 img_sl = slice(*sl) else: # default to take the whole image stack img_sl = slice(0, None, 1) if rescale is None: rescale = 1.0 aspect = None origin = None cmaps_labels = [] extracted_planes = [] start_planei = 0 if path and os.path.isdir(path): # builds animations from all files in a directory planes = sorted(glob.glob(os.path.join(path, "*")))[::interval] _logger.info("Importing images from %s: %s", path, planes) fnc = StackPlaneIO.import_img extracted_planes.append(planes) else: # load images from path and extract ROI based on slice parameters, # assuming 1st image is atlas, 2nd and beyond are labels-based imgs = [image5d] if labels_imgs is not None: for img in labels_imgs: if img is not None: imgs.append(img[None]) _setup_labels_cmaps(imgs, cmaps_labels) main_shape = None # z,y,x shape of 1st image for img in imgs: sl = img_sl img_shape = img.shape[1:4] if main_shape: if main_shape != img_shape: # scale slice bounds to the first image's shape scaling = np.divide(img_shape, main_shape) axis = plot_support.get_plane_axis(config.plane, True) sl = libmag.scale_slice(sl, scaling[axis], img_shape[axis]) else: main_shape = img_shape planes, aspect, origin = plot_support.extract_planes( img, sl, plane=config.plane) if offset is not None and roi_size is not None: # get ROI using transposed coordinates on transposed planes; # returns list planes = planes[:, offset[1]:offset[1] + roi_size[1], offset[0]:offset[0] + roi_size[0]] extracted_planes.append(planes) fnc = StackPlaneIO.process_plane if img_sl.start: start_planei = img_sl.start # store in stack worker stacker = StackPlaneIO() StackPlaneIO.interp_order = config.transform[ config.Transforms.INTERPOLATION] stacker.images = extracted_planes stacker.fn_process = fnc stacker.rescale = rescale stacker.start_planei = start_planei stacker.origin = origin stacker.aspect = aspect stacker.cmaps_labels = cmaps_labels stacker.img_slice = img_sl return stacker
def stack_to_ax_imgs(ax, image5d, path=None, offset=None, roi_size=None, slice_vals=None, rescale=None, labels_imgs=None, multiplane=False, fit=False): """Export a stack of images in a directory or a single volumetric image and associated labels images to :obj:`matplotlib.image.AxesImage` objects for export. Args: ax (:obj:`plt.Axes`): Matplotlib axes on which to plot images. image5d: Images as a 4/5D Numpy array (t,z,y,x[c]). Can be None if ``path`` is set. path: Path to an image directory from which all files will be imported in Python sorted order, taking precedence over ``imaged5d``; defaults to None. offset: Tuple of offset given in user order (x, y, z); defaults to None. Requires ``roi_size`` to not be None. roi_size: Size of the region of interest in user order (x, y, z); defaults to None. Requires ``offset`` to not be None. slice_vals: List from which to construct a slice object to extract only a portion of the image. Defaults to None, which will give the whole image. If ``offset`` and ``roi_size`` are also given, ``slice_vals`` will only be used for its interval term. rescale: Rescaling factor for each image, performed on a plane-by-plane basis; defaults to None, in which case 1.0 will be used. labels_imgs: Sequence of labels-based images as a Numpy z,y,x arrays, typically including labels and borders images; defaults to None. multiplane: True to extract the images as an animated GIF or movie file; False to extract a single plane only. Defaults to False. fit (bool): True to fit the figure frame to the resulting image. Returns: List[:obj:`matplotlib.image.AxesImage`]: List of image objects. """ print("Starting image stack export") # build "z" slice, which will be applied to the transposed image; # reduce image to 1 plane if in single mode interval = 1 if offset is not None and roi_size is not None: # transpose coordinates to given plane _, arrs_1d = plot_support.transpose_images( config.plane, arrs_1d=[offset[::-1], roi_size[::-1]]) offset = arrs_1d[0][::-1] roi_size = arrs_1d[1][::-1] # ROI offset and size take precedence over slice vals except # for use of the interval term interval = None if slice_vals is not None and len(slice_vals) > 2: interval = slice_vals[2] size = roi_size[2] if multiplane else 1 img_sl = slice(offset[2], offset[2] + size, interval) if interval is not None and interval < 0: # reverse start/stop order to iterate backward img_sl = slice(img_sl.stop, img_sl.start, interval) print("using ROI offset {}, size {}, {}".format(offset, size, img_sl)) elif slice_vals is not None: # build directly from slice vals unless not an animation if multiplane: img_sl = slice(*slice_vals) else: # single plane only for non-animation img_sl = slice(slice_vals[0], slice_vals[0] + 1) else: # default to take the whole image stack img_sl = slice(None, None) if rescale is None: rescale = 1.0 aspect = None origin = None cmaps_labels = [] extracted_planes = [] start_planei = 0 if path and os.path.isdir(path): # builds animations from all files in a directory planes = sorted(glob.glob(os.path.join(path, "*")))[::interval] print(planes) fnc = StackPlaneIO.import_img extracted_planes.append(planes) else: # load images from path and extract ROI based on slice parameters, # assuming 1st image is atlas, 2nd and beyond are labels-based imgs = [image5d] if labels_imgs is not None: for img in labels_imgs: if img is not None: imgs.append(img[None]) _setup_labels_cmaps(imgs, cmaps_labels) main_shape = None # z,y,x shape of 1st image for img in imgs: sl = img_sl img_shape = img.shape[1:4] if main_shape: if main_shape != img_shape: # scale slice bounds to the first image's shape scaling = np.divide(img_shape, main_shape) axis = plot_support.get_plane_axis(config.plane, True) sl = libmag.scale_slice(sl, scaling[axis], img_shape[axis]) else: main_shape = img_shape planes, aspect, origin = plot_support.extract_planes( img, sl, plane=config.plane) if offset is not None and roi_size is not None: # get ROI using transposed coordinates on transposed planes; # returns list planes = planes[:, offset[1]:offset[1] + roi_size[1], offset[0]:offset[0] + roi_size[0]] extracted_planes.append(planes) fnc = StackPlaneIO.process_plane if img_sl.start: start_planei = img_sl.start # export planes plotted_imgs = _build_stack( ax, extracted_planes, fnc, rescale, aspect=aspect, origin=origin, cmaps_labels=cmaps_labels, scale_bar=config.plot_labels[config.PlotLabels.SCALE_BAR], start_planei=start_planei) if fit and plotted_imgs: # fit frame to first plane's first available image ax_img = None for ax_img in plotted_imgs[0]: # images may be None if alpha set to 0 if ax_img is not None: break if ax_img is not None: plot_support.fit_frame_to_image(ax_img.figure, ax_img.get_array().shape, aspect) return plotted_imgs