Keras ImageDataGenerator для сегментации с изображениями и масками в отдельных каталогах - PullRequest
1 голос
/ 09 июня 2019

Я пытаюсь построить модель семантической сегментации, используя tensorflow.keras. Набор данных, который я использую, содержит изображения и маски, хранящиеся в отдельных каталогах, и каждое имя файла имеет идентификатор для сопоставления файла изображения с соответствующей маской.

Ниже приведена структура моего каталога наборов данных:

new
   - rendered_imges
      - render
         - image_1.tif
         - image_2.tif
         - image_3.tif
   - ground_truths
      - masks
         - mask_1.tif
         - mask_2.tif
         - mask_3.tif

В приведенной выше структуре каталогов image_{i}.tif соответствует mask_{i}.tif.

Я попытался написать ImageDataGenerator для увеличения как изображений, так и соответствующих им масок точно таким же образом. Мой подход был следующим:

SEED = 100

image_data_generator = ImageDataGenerator(
    width_shift_range = 0.1,
    height_shift_range = 0.1,
    rotation_range = 10,
    zoom_range = 0.1
).flow_from_directory('./new/rendered_images', batch_size = 16, target_size = (150, 150), seed = SEED)

mask_data_generator = ImageDataGenerator(
    width_shift_range = 0.1,
    height_shift_range = 0.1,
    rotation_range = 10,
    zoom_range = 0.1
).flow_from_directory('./new/ground_truths', batch_size = 16, target_size = (150, 150), seed = SEED)

При использовании вышеизложенного подхода, хотя к изображению и маске применяются одни и те же дополнения, изображения не соединяются с соответствующими масками в соответствии с именами файлов. Было бы замечательно, если бы кто-то мог предложить способ сделать это правильно, используя Keras или Tensorflow.

1 Ответ

2 голосов
/ 10 июня 2019

Вам потребуется создать новую функцию, которая будет генерировать как тренировочный образ, так и соответствующую маску, которую вы будете использовать для подачи в метод fit_generator.В частности, способ fit_generator заключается в том, чтобы получить последовательность кортежей, в которой первый элемент кортежа является изображением, а второй элемент кортежа - ожидаемым выходным сигналом.Просто используя генератор данных сам по себе, подкаталоги будут неявно кодировать ожидаемую метку изображения.Это, конечно, больше не тот случай, когда вы пытаетесь выполнить семантическую сегментацию.

Поэтому создайте новую функцию, которая будет выводить коллекцию кортежей, которые дают вам изображения и маска.Таким образом, вы просто возьмете два ImageDataGenerators, которые вы создали, zip их вместе, а затем получите цикл, который будет выдавать каждую серию обучающих изображений и ожидаемых выходных меток.

Одна последняя вещь, которая мне нужнаСледует отметить, что имена файлов для обоих каталогов должны совпадать с , если вы хотите успешно соединить изображение и соответствующую маску.Например, если у вас есть тренировочный образ с именем 1.tif в вашем подкаталоге rendered_imges/render, вам нужно будет указать имя соответствующего производителя в ground_truths/mask.Причина в том, что даже если вы сопоставляете начальные числа, он будет случайным образом выбирать имена файлов перед загрузкой изображений в память, поэтому для обеспечения того же порядка выбора среди обучающих изображений и соответствующих масок их имена также должныматч.Убедитесь, что вы делаете это, прежде чем мы продолжим.

Поэтому сделайте что-то вроде этого:

def my_image_mask_generator(image_data_generator, mask_data_generator):
    train_generator = zip(image_data_generator, mask_data_generator)
    for (img, mask) in train_generator:
        yield (img, mask)

Затем создайте генераторы данных, как вы это делали обычно:

SEED = 100

image_data_generator = ImageDataGenerator(
    width_shift_range = 0.1,
    height_shift_range = 0.1,
    rotation_range = 10,
    zoom_range = 0.1
).flow_from_directory('./new/rendered_images', batch_size = 16, target_size = (150, 150), seed = SEED)

mask_data_generator = ImageDataGenerator(
    width_shift_range = 0.1,
    height_shift_range = 0.1,
    rotation_range = 10,
    zoom_range = 0.1
).flow_from_directory('./new/ground_truths', batch_size = 16, target_size = (150, 150), seed = SEED)

Наконец, вызовите метод fit_generator в вашей модели.Предполагая, что вы уже правильно построили модель:

from keras.optimizers import Adam
# Your other related imports here...

# Create custom generator for training images and masks
my_generator = my_image_mask_generator(image_data_generator, mask_data_generator)

model = ... # Define your model here
# Compile your model here
model.compile(optimizer = Adam(lr = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy'])

# Train your model here
model.fit_generator(my_generator,...)

Обратите внимание, что, учитывая структуру каталогов, похоже, что вы выполняете бинарную сегментацию для каждого изображения, поэтому я выбрал бинарную кросс-энтропию в качествефункция потерь.

...