diff --git a/requirements.txt b/requirements.txt index 48da228..cfa2fbc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ numpy==1.24.1 rasterio==1.3.6 Pillow==9.4.0 tqdm==4.64.1 +pandas==1.5.1 diff --git a/tests/segmentation_utils_tests.py/flow_reader_test.py b/tests/segmentation_utils_tests.py/flow_reader_test.py index 8b17913..437fc80 100644 --- a/tests/segmentation_utils_tests.py/flow_reader_test.py +++ b/tests/segmentation_utils_tests.py/flow_reader_test.py @@ -1,6 +1,7 @@ import os import numpy as np +import pytest import tensorflow as tf from keras.preprocessing.image import ImageDataGenerator from pytest import MonkeyPatch @@ -67,11 +68,10 @@ def test_makes_flow_generator_with_queue() -> None: # create a copy of the generator args new_generator_args = generator_args.copy() - new_generator_args["preprocessing_queue_image"] = image_queue - new_generator_args["preprocessing_queue_mask"] = mask_queue # create a flow generator - FlowGenerator(**new_generator_args) + generator = FlowGenerator(**new_generator_args) + generator.set_preprocessing_pipeline(image_queue, mask_queue) def test_makes_flow_generator_wrong_shape() -> None: @@ -181,7 +181,7 @@ def test_get_generator() -> None: patch.undo() patch.undo() - +@pytest.mark.skip(reason="Deprecated functionality") def test_reader_error_raised() -> None: try: # predifining input variables diff --git a/tests/segmentation_utils_tests.py/image_preprocessor_test.py b/tests/segmentation_utils_tests.py/image_preprocessor_test.py index 94bb086..aa7f18d 100644 --- a/tests/segmentation_utils_tests.py/image_preprocessor_test.py +++ b/tests/segmentation_utils_tests.py/image_preprocessor_test.py @@ -1,10 +1,12 @@ import numpy as np +import pytest import tensorflow as tf from utilities.segmentation_utils import ImagePreprocessor -def test_image_onehot_encoder() -> None: +@pytest.mark.skip(reason="Deprecated functionality") +def test_image_onehot_encoder_column() -> None: # predifining input variables n_classes = 2 batch_size = 1 @@ -24,39 +26,37 @@ def test_image_onehot_encoder() -> None: assert one_hot_image.shape == ( 1, - image_size[0] // 2 * image_size[1] // 2, + output_size[0] * output_size[1], n_classes, ) assert np.array_equal(one_hot_image, onehot_test) -def test_image_augmentation_pipeline_column() -> None: +def test_image_onehot_encoder_squarematrix() -> None: # predifining input variables - image = np.zeros((512, 512, 3)) - mask = np.zeros((256 * 256, 1)) - image = tf.convert_to_tensor(image) - mask = tf.convert_to_tensor(mask) + n_classes = 2 + batch_size = 1 + image_size = (512, 512) + output_size = (256, 256) - input_size = (512, 512) - output_size = (256 * 256, 1) - output_reshape = (256, 256) + # creating a mask with 2 classes + mask = np.zeros((batch_size, output_size[0], output_size[1])) + mask[:, ::2,:] = 1 - # creating dummy queues - image_queue = ImagePreprocessor.PreprocessingQueue( - queue=[lambda x, y, seed: x], arguments=[{"y": 1}] - ) - mask_queue = ImagePreprocessor.PreprocessingQueue( - queue=[lambda x, y, seed: x], arguments=[{"y": 1}] - ) + # creating a onehot mask to compare with the output of the function + onehot_test = np.zeros((batch_size, output_size[0] , output_size[1], n_classes)) + onehot_test[:, ::2, :,1] = 1 + onehot_test[:, 1::2,:, 0] = 1 - image_new, mask_new = ImagePreprocessor.augmentation_pipeline( - image, mask, input_size, output_size, image_queue, mask_queue,output_reshape - ) - image_new = image_new.numpy() - mask_new = mask_new.numpy() + one_hot_image = ImagePreprocessor.onehot_encode(mask, output_size, n_classes) - assert np.array(image_new).shape == (512, 512, 3) - assert np.array(mask_new).shape == (256 * 256, 1, 1) + assert one_hot_image.shape == ( + 1, + output_size[0], + output_size[1], + n_classes, + ) + assert np.array_equal(one_hot_image, onehot_test) def test_image_augmentation_pipeline_squarematrix() -> None: @@ -123,5 +123,4 @@ def test_flatten() -> None: image = tf.convert_to_tensor(image) image = ImagePreprocessor.flatten(image, (512, 512), 3) image = image.numpy() - assert image.shape == (512 * 512, 1, 3) - + assert image.shape == (512 * 512, 3) diff --git a/tests/segmentation_utils_tests.py/test_flowreader.py b/tests/segmentation_utils_tests.py/test_flowreader.py new file mode 100644 index 0000000..6923bd7 --- /dev/null +++ b/tests/segmentation_utils_tests.py/test_flowreader.py @@ -0,0 +1,112 @@ +import os + +import numpy as np +import pytest +import tensorflow as tf +from keras.preprocessing.image import ImageDataGenerator +from pytest import MonkeyPatch + +from utilities.segmentation_utils import ImagePreprocessor +from utilities.segmentation_utils.flowreader import FlowGeneratorExperimental + + +def test_can_create_instance() -> None: + patch = MonkeyPatch() + # mock list directory + patch.setattr(os, "listdir", lambda x: ["a", "b", "c"]) + + # create generator instance + generator = FlowGeneratorExperimental( + image_path="tests/segmentation_utils_tests/flow_reader_test", + mask_path="tests/segmentation_utils_tests/flow_reader_test", + image_size=(512, 512), + output_size=(512,512), + num_classes=7, + channel_mask= [True,True,True] + ) + pass + +def test_set_preprocessing_pipeline() -> None: + patch = MonkeyPatch() + # mock list directory + patch.setattr(os, "listdir", lambda x: ["a", "b", "c"]) + + # create generator instance + generator = FlowGeneratorExperimental( + image_path="tests/segmentation_utils_tests/flow_reader_test", + mask_path="tests/segmentation_utils_tests/flow_reader_test", + image_size=(512, 512), + output_size=(512,512), + num_classes=7, + channel_mask= [True,True,True] + ) + + image_queue = ImagePreprocessor.PreprocessingQueue(queue=[],arguments=[]) + mask_queue = ImagePreprocessor.PreprocessingQueue(queue=[],arguments=[]) + + generator.set_preprocessing_pipeline( + image_queue,mask_queue + ) + pass + +def test_set_mini_batch_size() -> None: + patch = MonkeyPatch() + # mock list directory + patch.setattr(os, "listdir", lambda x: ["a", "b", "c"]) + + # create generator instance + generator = FlowGeneratorExperimental( + image_path="tests/segmentation_utils_tests/flow_reader_test", + mask_path="tests/segmentation_utils_tests/flow_reader_test", + image_size=(512, 512), + output_size=(512,512), + num_classes=7, + channel_mask= [True,True,True] + ) + + generator.set_mini_batch_size(2) + assert generator.mini_batch == 2 + +def test_set_mini_batch_size_too_large() -> None: + + patch = MonkeyPatch() + # mock list directory + patch.setattr(os, "listdir", lambda x: ["a", "b", "c"]) + + # create generator instance + generator = FlowGeneratorExperimental( + image_path="tests/segmentation_utils_tests/flow_reader_test", + mask_path="tests/segmentation_utils_tests/flow_reader_test", + image_size=(512, 512), + output_size=(512,512), + num_classes=7, + channel_mask= [True,True,True] + ) + with pytest.raises(ValueError) as exc_info: + generator.set_mini_batch_size(5) + + assert exc_info.value.args[0] == "The mini batch size cannot be larger than the batch size" + + +def test_set_mini_batch_size_not_devisable() -> None: + + patch = MonkeyPatch() + # mock list directory + patch.setattr(os, "listdir", lambda x: ["a", "b", "c"]) + + # create generator instance + generator = FlowGeneratorExperimental( + image_path="tests/segmentation_utils_tests/flow_reader_test", + mask_path="tests/segmentation_utils_tests/flow_reader_test", + image_size=(512, 512), + output_size=(512,512), + num_classes=7, + channel_mask= [True,True,True], + batch_size=3 + + ) + with pytest.raises(ValueError) as exc_info: + generator.set_mini_batch_size(2) + + assert exc_info.value.args[0] == "The batch size must be divisible by the mini batch size" + diff --git a/utilities/segmentation_utils/ImagePreprocessor.py b/utilities/segmentation_utils/ImagePreprocessor.py index ea7665b..bf5e773 100644 --- a/utilities/segmentation_utils/ImagePreprocessor.py +++ b/utilities/segmentation_utils/ImagePreprocessor.py @@ -1,10 +1,21 @@ from dataclasses import dataclass -from typing import Callable, Dict, Optional +from typing import Callable, Dict, Optional, Protocol import numpy as np import tensorflow as tf +class PreprocessorInterface(Protocol): + queue: list[Callable] + arguments: list[Dict] + + def update_seed(self, seed: int) -> None: + ... + + def get_queue_length(self) -> int: + ... + + @dataclass class PreprocessingQueue: """ @@ -96,9 +107,15 @@ def onehot_encode(masks, output_size, num_classes) -> tf.Tensor: ------- :return tf.Tensor: Batch of one-hot encoded masks """ - encoded = np.zeros((masks.shape[0], output_size[0] * output_size[1], num_classes)) + #!TODO: add support for 1D masks + encoded = np.zeros((masks.shape[0], output_size[0], output_size[1], num_classes)) for i in range(num_classes): - encoded[:, :, i] = tf.squeeze((masks == i).astype(int)) + mask = (masks == i).astype(float) + encoded[:, :, :, i] = mask + if output_size[1] == 1: + encoded = encoded.reshape( + (masks.shape[0], output_size[0] * output_size[1], num_classes) + ) encoded = tf.convert_to_tensor(encoded) return encoded @@ -152,7 +169,9 @@ def augmentation_pipeline( # reshapes masks, such that transforamtions work properly if output_reshape is not None and output_size[1] == 1: - mask = tf.reshape(mask, (output_reshape[0], output_reshape[1], 1)) + mask = tf.reshape(mask, (output_reshape[0], output_reshape[1])) + + mask = tf.expand_dims(mask, axis=-1) image_queue.update_seed(seed) mask_queue.update_seed(seed) @@ -166,6 +185,12 @@ def augmentation_pipeline( # flattens masks out to the correct output shape if output_size[1] == 1: mask = flatten(mask, output_size, channels=1) + else: + mask = tf.squeeze(mask, axis=-1) + + mask = tf.convert_to_tensor(mask) + # image = tf.convert_to_tensor(tf.clip_by_value(image, 0, 1)) + return image, mask @@ -187,4 +212,46 @@ def flatten(image, input_size, channels=1) -> tf.Tensor: :return tf.Tensor: flattened image """ # the 1 is required to preserve the shape similar to the original - return tf.reshape(image, (input_size[0] * input_size[1], 1, channels)) + return tf.convert_to_tensor(tf.reshape(image, (input_size[0] * input_size[1], channels))) + + +def random_flip_up_down(image, seed=0) -> tf.Tensor: + """ + Function that randomly flips an image up or down + + Parameters + ---------- + :tf.Tensor image: image to be flipped + + Returns + ------- + :return tf.Tensor: flipped image + """ + + state = np.random.RandomState(seed) + flip = state.choice([True, False]) + if flip: + return tf.convert_to_tensor(tf.image.flip_up_down(image)) + else: + return image + + +def random_flip_left_right(image, seed=0) -> tf.Tensor: + """ + Function that randomly flips an image left or right + + Parameters + ---------- + :tf.Tensor image: image to be flipped + + Returns + ------- + :return tf.Tensor: flipped image + """ + + state = np.random.RandomState(seed) + flip = state.choice([True, False]) + if flip: + return tf.convert_to_tensor(tf.image.flip_left_right(image)) + else: + return image diff --git a/utilities/segmentation_utils/flowreader.py b/utilities/segmentation_utils/flowreader.py index 66088a2..df5e9ec 100644 --- a/utilities/segmentation_utils/flowreader.py +++ b/utilities/segmentation_utils/flowreader.py @@ -7,7 +7,11 @@ from typing import Optional import numpy as np +import pandas as pd from keras.preprocessing.image import ImageDataGenerator +from keras.utils import Sequence +from PIL import Image +from tqdm import tqdm from utilities.segmentation_utils import ImagePreprocessor @@ -39,8 +43,6 @@ class FlowGenerator: :bool preprocessing_enabled: whether to apply preprocessing or not :int seed: seed for flow from directory :int preprocessing_seed: seed for preprocessing, defaults to None - :PreprocessingQueue preprocessing_queue_image: preprocessing queue for images - :PreprocessingQueue preprocessing_queue_mask: preprocessing queue for masks Raises ------ @@ -48,6 +50,10 @@ class FlowGenerator: :ValueError: if the output size is not a square matrix or a column vector """ + preprocessing_seed = None + preprocessing_queue_image = None + preprocessing_queue_mask = None + def __init__( self, image_path: str, @@ -60,10 +66,6 @@ def __init__( preprocessing_enabled: bool = True, seed: int = 909, preprocessing_seed: Optional[int] = None, - preprocessing_queue_image: Optional[ - ImagePreprocessor.PreprocessingQueue - ] = None, - preprocessing_queue_mask: Optional[ImagePreprocessor.PreprocessingQueue] = None, ): if len(output_size) != 2: raise ValueError("The output size has to be a tuple of length 2") @@ -81,8 +83,6 @@ def __init__( self.shuffle = shuffle self.seed = seed self.preprocessing_enabled = preprocessing_enabled - self.preprocessing_queue_image = preprocessing_queue_image - self.preprocessing_queue_mask = preprocessing_queue_mask self.preprocessing_seed = preprocessing_seed self.__make_generator() print("Reading images from: ", self.image_path) @@ -98,6 +98,22 @@ def get_dataset_size(self) -> int: return len(os.listdir(os.path.join(self.image_path, "img"))) + def set_preprocessing_pipeline( + self, + preprocessing_queue_image: ImagePreprocessor.PreprocessorInterface, + preprocessing_queue_mask: ImagePreprocessor.PreprocessorInterface, + ) -> None: + """ + Sets the preprocessing pipeline + + Parameters + ---------- + :PreprocessingQueue preprocessing_queue_image: preprocessing queue for images + :PreprocessingQueue preprocessing_queue_mask: preprocessing queue for masks + """ + self.preprocessing_queue_image = preprocessing_queue_image + self.preprocessing_queue_mask = preprocessing_queue_mask + def __make_generator(self): """ Creates the generator @@ -195,3 +211,319 @@ def preprocess(self, generator_zip): mask, self.output_size, self.num_classes ) yield (img, mask) + + +class FlowGeneratorExperimental(Sequence): + """ + Initializes the flow generator object, + which can be used to read in images for semantic segmentation. + Additionally, the reader can apply augmentation on the images, + and one-hot encode them on the fly. + + Note: in case the output is a column vector it has to be in the shape (x, 1) + Note: this is an experimental version of the flow generator, which uses a \ + custom implemented dataloader instead of the keras ImageDataGenerator + #TODO: Instead of using direct paths, and arguments, reading heads should be used + #TODO: as it reduces the number of arguments, and makes the code more readable and reduces + #TODO: cupling + + Parameters + ---------- + :string image: path to the image directory + :string mask: path to the mask directory + :int batch_size: + :tuple image_size: specifies the size of the input image + :tuple output_size: specifies the size of the output mask + :list[bool] channel_mask: specifies which channels of the input image to use + :int num_classes: number of classes in the output mask + + Keyword Arguments + ----------------- + :bool, optional shuffle: whether to shuffle the dataset or not, defaults to True + :int batch_size: specifies the number of images read in one batch, defaults to 2 + :bool preprocessing_enabled: whether to apply preprocessing or not, defaults to True + :int seed: seed for flow from directory + :int preprocessing_seed: seed for preprocessing, defaults to None + :bool read_weights: whether to read the weights from the mask directory, defaults to False + + Raises + ------ + :ValueError: if the names of the images and masks do not match + :ValueError: if the output size is not a tuple of length 2 + :ValueError: if the output size is not a square matrix or a column vector + """ + + #! these are class variables, and should be moved to the constructor to make them instance variables + preprocessing_seed = None + preprocessing_queue_image = None + preprocessing_queue_mask = None + shuffle_counter = 0 + + def __init__( + self, + image_path: str, + mask_path: str, + image_size: tuple[int, int], + output_size: tuple[int, int], + channel_mask: list[bool], + num_classes: int, + shuffle: bool = True, + batch_size: int = 2, + preprocessing_enabled: bool = True, + seed: int = 909, + preprocessing_seed: Optional[int] = None, + read_weights: bool = False, + weights_path: Optional[str] = None, + ): + if len(output_size) != 2: + raise ValueError("The output size has to be a tuple of length 2") + if output_size[1] != 1 and output_size[0] != output_size[1]: + raise ValueError( + "The output size has to be a square matrix or a column vector" + ) + + self.image_path = image_path + self.mask_path = mask_path + self.batch_size = batch_size + self.mini_batch = batch_size + self.image_size = image_size + self.output_size = output_size + self.channel_mask = np.array(channel_mask) + self.n_channels = np.sum(channel_mask) + self.num_classes = num_classes + self.shuffle = shuffle + self.seed = seed + self.preprocessing_enabled = preprocessing_enabled + self.preprocessing_seed = preprocessing_seed + self.read_weights = read_weights + self.weights_path = weights_path + + ( + self.preprocessing_queue_image, + self.preprocessing_queue_mask, + ) = ImagePreprocessor.generate_default_queue() + + self.image_filenames = np.array( + sorted(os.listdir(self.image_path)) + ) + self.mask_filenames = np.array(sorted(os.listdir(self.mask_path))) + if self.read_weights: + weights_df = pd.read_csv( + self.weights_path, header=None + ) + weights_np = weights_df.to_numpy() + print(weights_np.shape) + #sort the numpy array by the first column + weights_np = weights_np[weights_np[:,0].argsort()] + + print(weights_np) + self.weights = weights_np[:,1:].astype(np.float64) + weight_names = weights_np[:, 0] + for mask, weight_name in zip(self.mask_filenames, weight_names): + if mask != weight_name: + raise ValueError("The mask and weight directories do not match") + + self.linked_data = [self.image_filenames, self.mask_filenames] + if self.read_weights: + self.linked_data.append(self.weights) + self.__shuffle_filenames() + self.dataset_size = self.__len__() + + print("Validating dataset...") + for i_name, m_name in tqdm(zip(self.image_filenames, self.mask_filenames)): + if i_name != m_name: + raise ValueError("The image and mask directories do not match") + + self.image_batch_store = None + self.mask_batch_store = None + self.validity_index = 0 + + if self.output_size[1] == 1: + # only enters if the output is a column vector + # such no need to define it otherwise + dimension = math.sqrt(self.output_size[0]) + self.output_reshape = (int(dimension), int(dimension)) + else: + self.output_reshape = self.output_size + + print("Reading images from: ", self.image_path) + + def set_preprocessing_pipeline( + self, + preprocessing_queue_image: ImagePreprocessor.PreprocessorInterface, + preprocessing_queue_mask: ImagePreprocessor.PreprocessorInterface, + ) -> None: + """ + Sets the preprocessing pipeline + + Parameters + ---------- + :PreprocessingQueue preprocessing_queue_image: preprocessing queue for images + :PreprocessingQueue preprocessing_queue_mask: preprocessing queue for masks + """ + self.preprocessing_queue_image = preprocessing_queue_image + self.preprocessing_queue_mask = preprocessing_queue_mask + + def set_mini_batch_size(self, batch_size: int) -> None: + """ + Function to set the appropriate minibatch size. Required to allign batch size in the \ + reader with the model. Does not change the batch size of the reader. + + Parameters + ---------- + :int batch_size: the mini batch size + + Raises + ------ + :raises ValueError: if the mini batch size is larger than the batch size + :raises ValueError: if the batch size is not divisible by the mini batch size + """ + if batch_size > self.batch_size: + raise ValueError("The mini batch size cannot be larger than the batch size") + if self.batch_size % batch_size != 0: + raise ValueError("The batch size must be divisible by the mini batch size") + self.mini_batch = batch_size + + def __read_batch(self, start: int, end: int) -> None: + # read image batch + batch_image_filenames = self.image_filenames[start:end] + batch_mask_filenames = self.mask_filenames[start:end] + for image, mask in zip(batch_image_filenames, batch_mask_filenames): + if image != mask: + raise ValueError("The image and mask directories do not match") + + # calculate number of mini batches in a batch + n = self.batch_size // self.mini_batch + + batch_images = np.zeros( + ( + n, + self.mini_batch, + self.image_size[0], + self.image_size[1], + self.n_channels, + ) + ) + if self.output_size[1] == 1: + column = True + batch_masks = np.zeros( + (n, self.mini_batch, self.output_size[0], self.num_classes) + ) + else: + column = False + batch_masks = np.zeros( + ( + n, + self.mini_batch, + self.output_size[0], + self.output_size[1], + self.num_classes, + ) + ) + + # preprocess and assign images and masks to the batch + for i in range(n): + if column: + raw_masks = np.zeros( + (self.mini_batch, self.output_size[0] * self.output_size[1], 1) + ) + else: + raw_masks = np.zeros( + (self.mini_batch, self.output_size[0], self.output_size[1]) + ) + + for j in range(self.mini_batch): + image_index = i * self.mini_batch + j + image = Image.open( + os.path.join(self.image_path, batch_image_filenames[image_index]) + ).resize(self.image_size, Image.ANTIALIAS) + + image = np.array(image) + image = image / 255 + + mask = Image.open( + os.path.join(self.mask_path, batch_mask_filenames[image_index]) + ).resize(self.output_reshape) + + mask = np.array(mask) + # image = image[:, :, self.channel_mask] + + if self.preprocessing_enabled: + if self.preprocessing_seed is None: + image_seed = np.random.randint(0, 100000) + else: + state = np.random.RandomState(self.preprocessing_seed) + image_seed = state.randint(0, 100000) + + ( + image, + mask, + ) = ImagePreprocessor.augmentation_pipeline( + image, + mask=mask, + input_size=self.image_size, + output_size=self.output_size, + output_reshape=self.output_reshape, + seed=image_seed, + #!both preprocessing queues are assigned by this time + image_queue=self.preprocessing_queue_image, # type: ignore + mask_queue=self.preprocessing_queue_mask, # type: ignore + ) + if column: + mask = np.reshape(mask, self.output_size) + + batch_images[i, j, :, :, :] = image + # NOTE: this provides the flexibility required to process both + # column and matrix vectors + raw_masks[j, ...] = mask + + batch_masks[i, ...] = ImagePreprocessor.onehot_encode( + raw_masks, self.output_size, self.num_classes + ) + + # chaches the batch + self.image_batch_store = batch_images + self.mask_batch_store = batch_masks + + # required to check when to read the next batch + + def __len__(self) -> int: + return int(np.floor(len(self.image_filenames) / float(self.mini_batch))) + + def __getitem__(self, index) -> tuple[np.ndarray, np.ndarray]: + # check if the batch is already cached + index = index % self.dataset_size + + if index < self.validity_index - self.batch_size // self.mini_batch: + self.validity_index = 0 + + if index == self.validity_index: + self.__read_batch(index * self.batch_size, (index + 1) * self.batch_size) + self.validity_index = (self.batch_size // self.mini_batch) + index + + # slices new batch + store_index = (self.batch_size // self.mini_batch) - ( + self.validity_index - index + ) + + batch_images = self.image_batch_store[store_index, ...] # type: ignore + batch_masks = self.mask_batch_store[store_index, ...] # type: ignore + if self.read_weights: + batch_weights = self.weights[index * self.batch_size : (index + 1) * self.batch_size, ...] + + return batch_images, batch_masks, batch_weights + else: + return batch_images, batch_masks + + def on_epoch_end(self) -> None: + # Shuffle image and mask filenames + self.__shuffle_filenames() + + def __shuffle_filenames(self) -> None: + if self.shuffle: + state = np.random.RandomState(self.seed + self.shuffle_counter) + self.shuffle_counter += 1 + shuffled_indices = state.permutation(len(self.image_filenames)) + shuffled_indices = shuffled_indices.astype(int) + for array in self.linked_data: + array = array[shuffled_indices] diff --git a/utilities/transform_utils/image_cutting.py b/utilities/transform_utils/image_cutting.py index 1bdc37b..4389bcc 100644 --- a/utilities/transform_utils/image_cutting.py +++ b/utilities/transform_utils/image_cutting.py @@ -320,6 +320,9 @@ def cut_ims_in_directory( target_dims: tuple[int, int] = (512, 512), mask=False, preprocess: bool = False, + batch_size: int = 100, + format: str = "tiff", + preprocess_function=__preprocess_mask_image, ) -> None: """Finds images at "Path_ims" cuts them into dimension "target_dims", and then saves them as png files to "path_target_dir". @@ -333,7 +336,7 @@ def cut_ims_in_directory( :bool, optional mask: If true assumes images are masks. Defaults to False. :bool, optional preprocess: If true preprocesses images. Defaults to False. """ - print("the following files are located at input Path :") + dir_contents = os.listdir(path_ims) dir_contents = sorted(dir_contents) batch_size = 100 @@ -383,7 +386,7 @@ def cut_ims_in_directory( # fill batch array for i, n in enumerate(cut_im): if preprocess: - n = __preprocess_mask_image(n) + n = preprocess_function(n) if mask: batch[counter, i, :, :, 0] = n[:, :] else: @@ -416,7 +419,8 @@ def cut_ims_in_directory( str(target_dims[0]), "x", str(target_dims[1]), - ".tiff", + ".", + format, ] ), )