def _run(self, *args, **kwargs): ncyc, nz, nch = self.config.n_cycles, self.config.n_z_planes, self.config.n_channels_per_cycle _validate_mode(self.mode) # If in "raw" mode, load a tile by accumlating individual grayscale images if self.mode == 'raw': # Tile should have shape (cycles, z, channel, height, width) img_cyc = [] for icyc in range(ncyc): img_ch = [] for ich in range(nch): img_z = [] for iz in range(nz): img_path = cytokit_io.get_raw_img_path(self.region_index, self.tile_index, icyc, ich, iz) img_path = osp.join(self.data_dir, img_path) img = cytokit_io.read_raw_microscope_image(img_path, self.raw_file_type) if img.ndim != 2: raise ValueError( 'Expecting raw image at path "{}" to have 2 dims but found shape {}' .format(img_path, img.shape) ) img_z.append(img) img_ch.append(np.stack(img_z, 0)) img_cyc.append(np.stack(img_ch, 1)) tile = np.stack(img_cyc, 0) # Otherwise assume that the tile has already been assembled and just read it in instead else: tx, ty = self.config.get_tile_coordinates(self.tile_index) img_path = cytokit_io.get_img_path(self.path_fmt_name, self.region_index, tx, ty) tile = cytokit_io.read_tile(osp.join(self.data_dir, img_path)) return tile
def test_raw_img_paths(self): cytokit.set_path_formats(cytokit.FF_DEFAULT) # Test raw image path generation with default settings path = cytokit_io.get_raw_img_path(ireg=0, itile=0, icyc=0, ich=0, iz=0) self.assertEqual('Cyc1_reg1/1_00001_Z001_CH1.tif', path) # Test raw image path generation with explicit overrides on index mappings cytokit.set_raw_index_symlinks( dict(region={1: 2}, cycle={1: 5}, z={1: 3}, channel={1: 9})) path = cytokit_io.get_raw_img_path(ireg=0, itile=0, icyc=0, ich=0, iz=0) self.assertEqual('Cyc5_reg2/2_00001_Z003_CH9.tif', path) cytokit.set_raw_index_symlinks({})
def get_tile_montage(config, image_dir, hyperstack, icyc=0, iz=0, ich=0, ireg=0, bw=0, bv_fn=None, allow_missing=False, imread_fn=None): """Generate a montage image for a specific cycle, z-plane, channel, and region This function supports both raw, flattened 2D images as well as consolidated, 5D hyperstacks (as determined by `hyperstack` argument) Args: config: Experiment configuration image_dir: Location of tiled images; These should include all z-planes, cycles, and channels in individual tif files (e.g. the output of the pre-processing or segmentation pipelines) hyperstack: Flag indicating whether or not images are 5D hyperstacks or flattened 2D images: - Hyperstacks are typically results from any sort of processing or segmentation step - Flattened 2D images are typically raw files generated directly from a microscope icyc: 0-based cycle index iz: 0-based z-plane index ich: 0-based channel index ireg: 0-based region index bw: Border width (in pixels) to add to each tile in the montage image, which useful for determining tile location within the montage; If <= 0, this parameter will do nothing bv_fn: Border value function with signature `fn(tile_x, tile_y) --> float`; if not given all border values are assigned a value of 0 allow_missing: Flag indicating whether or not to allow missing tiles into the montage; defaults to false and is generally only useful when debugging missing data imread_fn: When not using 5D hyperstacks (i.e. reading raw image files) this can be useful for cases when, for example, raw, single-channel files are actually 3 channel files with the first two channels blank (this happens w/ Keyence somehow). This function will take an image path and must return a single 2D image with shape (rows, cols) Returns: A (usually very large) 2D array containing all tiles stitched together """ tile_indexes = list(range(config.n_tiles_per_region)) tw, th = config.tile_width, config.tile_height tiles = [] for itile in tile_indexes: tx, ty = config.get_tile_coordinates(itile) # If operating on a hyperstack, extract the appropriate slice to add to the montage if hyperstack: path = cytokit_io.get_processor_img_path(ireg, tx, ty) path = osp.join(image_dir, path) if not osp.exists(path) and allow_missing: tile = np.zeros((th, tw)) else: tile = cytokit_io.read_tile(path) tile = tile[icyc, iz, ich, :, :] # Otherwise, assume raw acquisition files are to be loaded and then cropped before being added else: path = cytokit_io.get_raw_img_path(ireg, itile, icyc, ich, iz) path = osp.join(image_dir, path) if not osp.exists(path) and allow_missing: tile = np.zeros((th, tw)) else: tile = cytokit_io.read_image(path) if imread_fn is None else imread_fn(path) if tile.ndim != 2: raise ValueError( 'Expecting 2D image at path "{}" but shape found is {}. Consider using the ' '`imread_fn` argument to specify a custom function to open files or if already using it, ' 'make sure that results are 2D' .format(path, tile.shape) ) tile = tile_crop.apply_slice(tile, tile_crop.get_slice(config)) # Highlight borders, if configured to do so if bw > 0: bv = 0 if bv_fn is None else bv_fn(tx, ty) tile[0:bw, :] = bv tile[-bw:, :] = bv tile[:, 0:bw] = bv tile[:, -bw:] = bv # Add to montage tiles.append(tile) return core.montage(tiles, config)