Exemple #1
0
    def test_tile_stack(self):
        """Test tile_stack"""

        self.tile_inst.tile_stack()
        # Read and validate the saved metadata
        tile_dir = self.tile_inst.get_tile_dir()
        frames_meta = pd.read_csv(os.path.join(tile_dir, 'frames_meta.csv'))

        self.assertSetEqual(set(frames_meta.channel_idx.tolist()), {1})
        self.assertSetEqual(set(frames_meta.slice_idx.tolist()), {16, 17, 18})
        self.assertSetEqual(set(frames_meta.time_idx.tolist()), {5})
        self.assertSetEqual(set(frames_meta.pos_idx.tolist()), {7, 8})
        # 15 rows and step size 4, so it can take 3 full steps and 1 short step
        self.assertSetEqual(set(frames_meta.row_start.tolist()), {0, 4, 8, 10})
        # 11 cols and step size 4, so it can take 2 full steps and 1 short step
        self.assertSetEqual(set(frames_meta.col_start.tolist()), {0, 4, 6})

        # Read and validate tiles
        im_val = np.mean(norm_util.zscore(self.im / self.ff_im))
        im_norm = im_val * np.ones((3, 5, 5))
        im_val = np.mean(norm_util.zscore(self.im2 / self.ff_im))
        im2_norm = im_val * np.ones((3, 5, 5))
        for i, row in frames_meta.iterrows():
            tile = np.load(os.path.join(tile_dir, row.file_name))
            if row.pos_idx == 7:
                np.testing.assert_array_equal(tile, im_norm)
            else:
                np.testing.assert_array_equal(tile, im2_norm)
Exemple #2
0
    def test_preprocess_imstack(self):
        """Test preprocess_imstack"""
        im_stack = image_utils.preprocess_imstack(
            self.frames_meta,
            self.temp_path,
            depth=3,
            time_idx=self.time_idx,
            channel_idx=self.channel_idx,
            slice_idx=2,
            pos_idx=self.pos_idx,
            normalize_im=True,
        )
        np.testing.assert_equal(im_stack.shape, (32, 32, 3))
        exp_stack = normalize.zscore(self.sph[:, :, 1:4])
        np.testing.assert_array_equal(im_stack, exp_stack)

        # preprocess a 3D image
        im_stack = image_utils.preprocess_imstack(
            self.meta_3d,
            self.temp_path,
            depth=1,
            time_idx=0,
            channel_idx=1,
            slice_idx=0,
            pos_idx=1,
            normalize_im=True,
        )
        np.testing.assert_equal(im_stack.shape, (32, 32, 8))
Exemple #3
0
    def _read_one(tp_dir, channel_ids, fname, flat_field_dir=None):
        """Read one image set

        :param str tp_dir: timepoint dir
        :param list channel_ids: list of channels to read from
        :param str fname: fname of the image. Expects the fname to be the same
         in all channels
        :param str flat_field_dir: dir where flat field images are stored
        :returns: np.array of shape nb_channels, im_size (with or without
         flat field correction)
        """

        cur_images = []
        for ch in channel_ids:
            cur_fname = os.path.join(tp_dir, 'channel_{}'.format(ch), fname)
            cur_image = np.load(cur_fname)
            if flat_field_dir is not None:
                ff_fname = os.path.join(flat_field_dir,
                                        'flat-field_channel-{}.npy'.format(ch))
                ff_image = np.load(ff_fname)
                cur_image = image_utils.apply_flat_field_correction(
                    cur_image, flat_field_image=ff_image)
            cur_image = zscore(cur_image)
            cur_images.append(cur_image)
        cur_images = np.stack(cur_images)
        return cur_images
Exemple #4
0
def read_imstack(input_fnames,
                 flat_field_fname=None,
                 hist_clip_limits=None,
                 is_mask=False,
                 normalize_im=True):
    """
    Read the images in the fnames and assembles a stack.
    If images are masks, make sure they're boolean by setting >0 to True

    :param tuple input_fnames: tuple of input fnames with full path
    :param str flat_field_fname: fname of flat field image
    :param tuple hist_clip_limits: limits for histogram clipping
    :param bool is_mask: Indicator for if files contain masks
    :param bool normalize_im: Whether to zscore normalize im stack
    :return np.array: input stack flat_field correct and z-scored if regular
        images, booleans if they're masks
    """
    im_stack = []
    for idx, fname in enumerate(input_fnames):
        im = read_image(fname)
        if flat_field_fname is not None:
            # multiple flat field images are passed in case of mask generation
            if isinstance(flat_field_fname, (list, tuple)):
                flat_field_image = np.load(flat_field_fname[idx])
            else:
                flat_field_image = np.load(flat_field_fname)
            if not is_mask and not normalize_im:
                im = apply_flat_field_correction(
                    im,
                    flat_field_image=flat_field_image,
                )
        im_stack.append(im)

    input_image = np.stack(im_stack, axis=-1)
    # remove singular dimension for 3D images
    if len(input_image.shape) > 3:
        input_image = np.squeeze(input_image)
    if not is_mask:
        if hist_clip_limits is not None:
            input_image = normalize.hist_clipping(
                input_image,
                hist_clip_limits[0],
                hist_clip_limits[1]
            )
        if normalize_im:
            input_image = normalize.zscore(input_image)
    else:
        if input_image.dtype != bool:
            input_image = input_image > 0
    return input_image
Exemple #5
0
    def test_read_imstack(self):
        """Test read_imstack"""

        fnames = self.frames_meta['file_name'][:3]
        fnames = [os.path.join(self.temp_path, fname) for fname in fnames]
        # non-boolean
        im_stack = image_utils.read_imstack(fnames)
        exp_stack = normalize.zscore(self.sph[:, :, :3])
        np.testing.assert_equal(im_stack.shape, (32, 32, 3))
        np.testing.assert_array_equal(exp_stack[:, :, :3],
                                      im_stack)

        # read a 3D image
        im_stack = image_utils.read_imstack([self.sph_fname])
        np.testing.assert_equal(im_stack.shape, (32, 32, 8))

        # read multiple 3D images
        im_stack = image_utils.read_imstack((self.sph_fname, self.sph_fname))
        np.testing.assert_equal(im_stack.shape, (32, 32, 8, 2))
Exemple #6
0
    def _get_volume(self, fname_list, normalize=True, aug_idx=0):
        """
        Read tiles from fname_list and stack them into an image volume.

        :param list fname_list: list of file names of input/target images
        :param bool normalize: Whether to zscore normalize tiles
        :param int aug_idx: type of augmentation to be applied (if any)
        :return: np.ndarray of stacked images
        """
        image_volume = []
        for fname in fname_list:
            cur_tile = np.load(os.path.join(self.tile_dir, fname))
            if self.augmentations:
                cur_tile = self._augment_image(cur_tile, aug_idx)
            if self.squeeze:
                cur_tile = np.squeeze(cur_tile)
            image_volume.append(cur_tile)
        # Stack images channels first
        image_volume = np.stack(image_volume)
        if image_volume.dtype == bool:
            image_volume = image_volume.astype(np.float32)
        elif normalize:
            image_volume = norm.zscore(image_volume)
        return image_volume
Exemple #7
0
def preprocess_imstack(frames_metadata,
                       input_dir,
                       depth,
                       time_idx,
                       channel_idx,
                       slice_idx,
                       pos_idx,
                       flat_field_im=None,
                       hist_clip_limits=None,
                       normalize_im=False):
    """
    Preprocess image given by indices: flatfield correction, histogram
    clipping and z-score normalization is performed.

    :param pd.DataFrame frames_metadata: DF with meta info for all images
    :param str input_dir: dir containing input images
    :param int depth: num of slices in stack if 2.5D or depth for 3D
    :param int time_idx: Time index
    :param int channel_idx: Channel index
    :param int slice_idx: Slice (z) index
    :param int pos_idx: Position (FOV) index
    :param np.array flat_field_im: Flat field image for channel
    :param list hist_clip_limits: Limits for histogram clipping (size 2)
    :param bool normalize_im: indicator to normalize image based on z-score or not
    :return np.array im: 3D preprocessed image
    """
    margin = 0 if depth == 1 else depth // 2
    im_stack = []
    for z in range(slice_idx - margin, slice_idx + margin + 1):
        meta_idx = aux_utils.get_meta_idx(
            frames_metadata,
            time_idx,
            channel_idx,
            z,
            pos_idx,
        )
        file_path = os.path.join(
            input_dir,
            frames_metadata.loc[meta_idx, "file_name"],
        )
        im = read_image(file_path)
        # Only flatfield correct images that will be normalized
        if flat_field_im is not None and not normalize_im:
            im = apply_flat_field_correction(
                im,
                flat_field_image=flat_field_im,
            )
        im_stack.append(im)

    if len(im.shape) == 3:
        # each channel is tiled independently and stacked later in dataset cls
        im_stack = im
        assert depth == 1, 'more than one 3D volume gets read'
    else:
        # Stack images in same channel
        im_stack = np.stack(im_stack, axis=2)
    # normalize
    if hist_clip_limits is not None:
        im_stack = normalize.hist_clipping(
            im_stack,
            hist_clip_limits[0],
            hist_clip_limits[1],
        )
    if normalize_im:
        im_stack = normalize.zscore(im_stack)
    return im_stack
    def setUp(self):
        """
        Set up a directory with some images to generate frames_meta.csv for
        """
        self.tempdir = TempDirectory()
        self.temp_dir = self.tempdir.path
        self.model_dir = os.path.join(self.temp_dir, 'model_dir')
        self.pred_dir = os.path.join(self.model_dir, 'predictions')
        self.image_dir = os.path.join(self.temp_dir, 'image_dir')
        self.tempdir.makedir(self.model_dir)
        self.tempdir.makedir(self.pred_dir)
        self.tempdir.makedir(self.image_dir)
        # Write images
        self.time_idx = 5
        self.pos_idx = 7
        self.im = 1500 * np.ones((30, 20), dtype=np.uint16)
        im_add = np.zeros((30, 20), dtype=np.uint16)
        im_add[15:, :] = 10
        self.ext = '.tif'
        # Start frames meta file
        self.meta_name = 'frames_meta.csv'
        self.frames_meta = aux_utils.make_dataframe()

        for c in range(3):
            for z in range(5, 10):
                im_name = aux_utils.get_im_name(
                    channel_idx=c,
                    slice_idx=z,
                    time_idx=self.time_idx,
                    pos_idx=self.pos_idx,
                    ext=self.ext,
                )
                cv2.imwrite(os.path.join(self.image_dir, im_name), self.im)
                if c == 2:
                    norm_im = normalize.zscore(self.im + im_add).astype(np.float32)
                    cv2.imwrite(
                        os.path.join(self.pred_dir, im_name),
                        norm_im,
                    )
                self.frames_meta = self.frames_meta.append(
                    aux_utils.parse_idx_from_name(im_name),
                    ignore_index=True,
                )
        # Write metadata
        self.frames_meta.to_csv(
            os.path.join(self.image_dir, self.meta_name),
            sep=',',
        )
        # Write as test metadata in model dir too
        self.frames_meta.to_csv(
            os.path.join(self.model_dir, 'test_metadata.csv'),
            sep=',',
        )
        # Write split samples
        split_idx_fname = os.path.join(self.model_dir, 'split_samples.json')
        split_samples = {'test': [5, 6, 7, 8, 9]}
        aux_utils.write_json(split_samples, split_idx_fname)
        # Write config in model dir
        config = {
            'dataset': {
                'input_channels': [0, 1],
                'target_channels': [2],
                'split_by_column': 'slice_idx'
            },
            'network': {}
        }
        config_name = os.path.join(self.model_dir, 'config.yml')
        with open(config_name, 'w') as outfile:
            yaml.dump(config, outfile, default_flow_style=False)