volume_segmantics.data

1from volume_segmantics.data.settings_data import get_settings_data
2from volume_segmantics.data.slicers import TrainingDataSlicer
3
4__all__ = [get_settings_data, TrainingDataSlicer]
def get_settings_data(data: Union[pathlib.Path, dict, NoneType]) -> types.SimpleNamespace:
11def get_settings_data(data: Union[Path, dict, None]) -> SimpleNamespace:
12    """Creates an object holding settings data if a path to a YAML file or a
13    dictionary is given. If the data is None, an empty namespace is returned.
14    """
15    if data is None:
16        return SimpleNamespace()
17    elif isinstance(data, Path):
18        logging.info(f"Loading settings from {data}")
19        if data.exists():
20            with open(data, "r") as stream:
21                settings_dict = yaml.safe_load(stream)
22            return SimpleNamespace(**settings_dict)
23        else:
24            logging.error("Couldn't find settings file... Exiting!")
25            sys.exit(1)
26    elif isinstance(data, dict):
27        return SimpleNamespace(**data)

Creates an object holding settings data if a path to a YAML file or a dictionary is given. If the data is None, an empty namespace is returned.

class TrainingDataSlicer(volume_segmantics.data.base_data_manager.BaseDataManager):
 14class TrainingDataSlicer(BaseDataManager):
 15    """Class that converts 3d data volumes into 2d image slices on disk for
 16    model training.
 17    Slicing is carried in all of the xy (z), xz (y) and yz (x) planes.
 18
 19    Args:
 20        settings (SimpleNamespace): An initialised object with settings data.
 21    """
 22
 23    def __init__(
 24        self,
 25        data_vol: Union[str, np.ndarray],
 26        label_vol: Union[str, np.ndarray],
 27        settings,
 28    ):
 29        super().__init__(data_vol, settings)
 30        self.data_im_out_dir = None
 31        self.seg_im_out_dir = None
 32        self.multilabel = False
 33        self.settings = settings
 34        self.label_vol_path = utils.setup_path_if_exists(label_vol)
 35        if self.label_vol_path is not None:
 36            self.seg_vol, _ = utils.get_numpy_from_path(
 37                self.label_vol_path, internal_path=settings.seg_hdf5_path
 38            )
 39        elif isinstance(label_vol, np.ndarray):
 40            self.seg_vol = label_vol
 41        self.preprocess_labels()
 42
 43    def preprocess_labels(self):
 44        seg_classes = np.unique(self.seg_vol)
 45        self.num_seg_classes = len(seg_classes)
 46        if self.num_seg_classes > 2:
 47            self.multilabel = True
 48        logging.info(
 49            "Number of classes in segmentation dataset:" f" {self.num_seg_classes}"
 50        )
 51        logging.info(f"These classes are: {seg_classes}")
 52        if seg_classes[0] != 0 or not utils.sequential_labels(seg_classes):
 53            logging.info("Fixing label classes.")
 54            self.fix_label_classes(seg_classes)
 55        self.codes = [f"label_val_{i}" for i in seg_classes]
 56
 57    def fix_label_classes(self, seg_classes):
 58        """Changes the data values of classes in a segmented volume so that
 59        they start from zero.
 60
 61        Args:
 62            seg_classes(list): An ascending list of the labels in the volume.
 63        """
 64        for idx, current in enumerate(seg_classes):
 65            self.seg_vol[self.seg_vol == current] = idx
 66
 67    def output_data_slices(self, data_dir, prefix):
 68        """Wrapper method to intitiate slicing data volume to disk.
 69
 70        Args:
 71            data_dir (pathlib.Path): The path to the directory where images will be saved.
 72        """
 73        self.data_im_out_dir = data_dir
 74        logging.info("Slicing data volume and saving slices to disk")
 75        os.makedirs(data_dir, exist_ok=True)
 76        self.output_slices_to_disk(self.data_vol, data_dir, prefix)
 77
 78    def output_label_slices(self, data_dir, prefix):
 79        """Wrapper method to intitiate slicing label volume to disk.
 80
 81        Args:
 82            data_dir (pathlib.Path): The path to the directory where images will be saved.
 83        """
 84        self.seg_im_out_dir = data_dir
 85        logging.info("Slicing label volume and saving slices to disk")
 86        os.makedirs(data_dir, exist_ok=True)
 87        self.output_slices_to_disk(self.seg_vol, data_dir, prefix, label=True)
 88
 89    def output_slices_to_disk(self, data_arr, output_path, name_prefix, label=False):
 90        """Coordinates the slicing of an image volume in the three orthogonal
 91        planes to images on disk.
 92
 93        Args:
 94            data_arr (array): The data volume to be sliced.
 95            output_path (pathlib.Path): A Path object to the output directory.
 96            label (bool): Whether this is a label volume.
 97        """
 98        shape_tup = data_arr.shape
 99        ax_idx_pairs = utils.get_axis_index_pairs(shape_tup)
100        num_ims = utils.get_num_of_ims(shape_tup)
101        for axis, index in tqdm(ax_idx_pairs, total=num_ims):
102            out_path = output_path / f"{name_prefix}_{axis}_stack_{index}"
103            self.output_im(
104                utils.axis_index_to_slice(data_arr, axis, index), out_path, label
105            )
106
107    def output_im(self, data, path, label=False):
108        """Converts a slice of data into an image on disk.
109
110        Args:
111            data (numpy.array): The data slice to be converted.
112            path (str): The path of the image file including the filename prefix.
113            label (bool): Whether to convert values >1 to 1 for binary segmentation.
114        """
115        # TODO: Allow saving a higher bit depth
116        if data.dtype != np.uint8:
117            data = img_as_ubyte(data)
118        
119        if label and not self.multilabel:
120            data[data > 1] = 1
121        io.imsave(f"{path}.png", data, check_contrast=False)
122
123    def delete_image_dir(self, im_dir_path):
124        if im_dir_path.exists():
125            ims = list(im_dir_path.glob("*.png"))
126            logging.info(f"Deleting {len(ims)} images.")
127            for im in ims:
128                im.unlink()
129            logging.info(f"Deleting the empty directory.")
130            im_dir_path.rmdir()
131
132    def clean_up_slices(self):
133        """Wrapper function that cleans up data and label image slices."""
134        self.delete_image_dir(self.data_im_out_dir)
135        self.delete_image_dir(self.seg_im_out_dir)

Class that converts 3d data volumes into 2d image slices on disk for model training. Slicing is carried in all of the xy (z), xz (y) and yz (x) planes.

Args
  • settings (SimpleNamespace): An initialised object with settings data.
TrainingDataSlicer( data_vol: Union[str, numpy.ndarray], label_vol: Union[str, numpy.ndarray], settings)
23    def __init__(
24        self,
25        data_vol: Union[str, np.ndarray],
26        label_vol: Union[str, np.ndarray],
27        settings,
28    ):
29        super().__init__(data_vol, settings)
30        self.data_im_out_dir = None
31        self.seg_im_out_dir = None
32        self.multilabel = False
33        self.settings = settings
34        self.label_vol_path = utils.setup_path_if_exists(label_vol)
35        if self.label_vol_path is not None:
36            self.seg_vol, _ = utils.get_numpy_from_path(
37                self.label_vol_path, internal_path=settings.seg_hdf5_path
38            )
39        elif isinstance(label_vol, np.ndarray):
40            self.seg_vol = label_vol
41        self.preprocess_labels()
def preprocess_labels(self)
43    def preprocess_labels(self):
44        seg_classes = np.unique(self.seg_vol)
45        self.num_seg_classes = len(seg_classes)
46        if self.num_seg_classes > 2:
47            self.multilabel = True
48        logging.info(
49            "Number of classes in segmentation dataset:" f" {self.num_seg_classes}"
50        )
51        logging.info(f"These classes are: {seg_classes}")
52        if seg_classes[0] != 0 or not utils.sequential_labels(seg_classes):
53            logging.info("Fixing label classes.")
54            self.fix_label_classes(seg_classes)
55        self.codes = [f"label_val_{i}" for i in seg_classes]
def fix_label_classes(self, seg_classes)
57    def fix_label_classes(self, seg_classes):
58        """Changes the data values of classes in a segmented volume so that
59        they start from zero.
60
61        Args:
62            seg_classes(list): An ascending list of the labels in the volume.
63        """
64        for idx, current in enumerate(seg_classes):
65            self.seg_vol[self.seg_vol == current] = idx

Changes the data values of classes in a segmented volume so that they start from zero.

Args
  • seg_classes(list): An ascending list of the labels in the volume.
def output_data_slices(self, data_dir, prefix)
67    def output_data_slices(self, data_dir, prefix):
68        """Wrapper method to intitiate slicing data volume to disk.
69
70        Args:
71            data_dir (pathlib.Path): The path to the directory where images will be saved.
72        """
73        self.data_im_out_dir = data_dir
74        logging.info("Slicing data volume and saving slices to disk")
75        os.makedirs(data_dir, exist_ok=True)
76        self.output_slices_to_disk(self.data_vol, data_dir, prefix)

Wrapper method to intitiate slicing data volume to disk.

Args
  • data_dir (pathlib.Path): The path to the directory where images will be saved.
def output_label_slices(self, data_dir, prefix)
78    def output_label_slices(self, data_dir, prefix):
79        """Wrapper method to intitiate slicing label volume to disk.
80
81        Args:
82            data_dir (pathlib.Path): The path to the directory where images will be saved.
83        """
84        self.seg_im_out_dir = data_dir
85        logging.info("Slicing label volume and saving slices to disk")
86        os.makedirs(data_dir, exist_ok=True)
87        self.output_slices_to_disk(self.seg_vol, data_dir, prefix, label=True)

Wrapper method to intitiate slicing label volume to disk.

Args
  • data_dir (pathlib.Path): The path to the directory where images will be saved.
def output_slices_to_disk(self, data_arr, output_path, name_prefix, label=False)
 89    def output_slices_to_disk(self, data_arr, output_path, name_prefix, label=False):
 90        """Coordinates the slicing of an image volume in the three orthogonal
 91        planes to images on disk.
 92
 93        Args:
 94            data_arr (array): The data volume to be sliced.
 95            output_path (pathlib.Path): A Path object to the output directory.
 96            label (bool): Whether this is a label volume.
 97        """
 98        shape_tup = data_arr.shape
 99        ax_idx_pairs = utils.get_axis_index_pairs(shape_tup)
100        num_ims = utils.get_num_of_ims(shape_tup)
101        for axis, index in tqdm(ax_idx_pairs, total=num_ims):
102            out_path = output_path / f"{name_prefix}_{axis}_stack_{index}"
103            self.output_im(
104                utils.axis_index_to_slice(data_arr, axis, index), out_path, label
105            )

Coordinates the slicing of an image volume in the three orthogonal planes to images on disk.

Args
  • data_arr (array): The data volume to be sliced.
  • output_path (pathlib.Path): A Path object to the output directory.
  • label (bool): Whether this is a label volume.
def output_im(self, data, path, label=False)
107    def output_im(self, data, path, label=False):
108        """Converts a slice of data into an image on disk.
109
110        Args:
111            data (numpy.array): The data slice to be converted.
112            path (str): The path of the image file including the filename prefix.
113            label (bool): Whether to convert values >1 to 1 for binary segmentation.
114        """
115        # TODO: Allow saving a higher bit depth
116        if data.dtype != np.uint8:
117            data = img_as_ubyte(data)
118        
119        if label and not self.multilabel:
120            data[data > 1] = 1
121        io.imsave(f"{path}.png", data, check_contrast=False)

Converts a slice of data into an image on disk.

Args
  • data (numpy.array): The data slice to be converted.
  • path (str): The path of the image file including the filename prefix.
  • label (bool): Whether to convert values >1 to 1 for binary segmentation.
def delete_image_dir(self, im_dir_path)
123    def delete_image_dir(self, im_dir_path):
124        if im_dir_path.exists():
125            ims = list(im_dir_path.glob("*.png"))
126            logging.info(f"Deleting {len(ims)} images.")
127            for im in ims:
128                im.unlink()
129            logging.info(f"Deleting the empty directory.")
130            im_dir_path.rmdir()
def clean_up_slices(self)
132    def clean_up_slices(self):
133        """Wrapper function that cleans up data and label image slices."""
134        self.delete_image_dir(self.data_im_out_dir)
135        self.delete_image_dir(self.seg_im_out_dir)

Wrapper function that cleans up data and label image slices.

Inherited Members
volume_segmantics.data.base_data_manager.BaseDataManager
preprocess_data