Всем привет, я Юфэн. Сегодня я хочу поделиться с вами третьим докладом [Научим вас вручную] — сегментация изображения. Я не профессионал. Если есть какие-то ошибки, пожалуйста, критикуйте и исправьте меня.
Или старая поговорка: я Юфэн, я надеюсь, что статьи, которыми я делюсь, помогут вам и другим друзьям. Добро пожаловать, чтобы переслать или перепечатать!
Добро пожаловать в «Кодовое слово Юфэн»
1 Понимание сегментации изображений
Сегментация изображения относится к разделению изображения на несколько непересекающихся областей в соответствии с такими признаками, как оттенки серого, цвет, пространственная текстура, геометрическая форма и т. д., так что эти признаки проявляют согласованность или сходство в одной и той же области, но разные области заметно различаются. Проще говоря, на изображении цель отделена от фона. Для изображений в градациях серого пиксели внутри области обычно имеют сходство в градациях серого, а разрыв в градациях серого обычно существует на границе области.
1.1 Как сегментация выражается в компьютерах
Изображение существует в компьютере как набор чисел, и для каждого объекта на картинке компьютер понимает их через эти числа. Как показано на рисунке ниже, время для маркировки изображения отмечено цифрой 1, сумка отмечена цифрой 2, листья отмечены цифрой 3, тротуар отмечен цифрой 4, а здание отмечен номером 5. Компьютер использует эти числа для идентификации каждой категории. Сегментация изображения заключается в обнаружении краев этих разных чисел для сегментации.
1.2 Несколько подполей сегментации изображения
Семантическая сегментация: для изображения все объекты (включая фон) сегментируются, но для объектов одной категории невозможно различить разные лица. Сегментация экземпляра: сегментировать все объекты на изображении, кроме фона, и может различать разных людей в одной и той же категории (например, каждый человек представлен разным цветом на третьем изображении). Панорамная сегментация: на основе сегментации экземпляров можно сегментировать фоновые объекты. Связь между паноптической сегментацией и семантической сегментацией такова: если все категории являются вещественными, то паноптическая сегментация будет такой же, за исключением метрик и семантической сегментации. По сравнению с семантической сегментацией сложность панорамной сегментации заключается в том, чтобы позволить сетевой структуре различать разные экземпляры; Связь между панорамной сегментацией и сегментацией экземпляра такова: перекрытие не допускается при панорамной сегментации, но при сегментации экземпляра может; кроме того, сегментация экземпляра требует доверительной вероятности каждой сегментации, а панорамная сегментация - нет.
1.3 Традиционные методы сегментации
- Пороговый метод сегментации
- Методы сегментации изображений на основе областей
- Метод сегментации на основе обнаружения краев
- Метод сегментации изображения на основе вейвлет-преобразования
- Сегментация изображения на основе генетического алгоритма
- Метод сегментации на основе модели активного контура
1.4 Метод сегментации на основе глубокого обучения
ФКН Ю-Нет ДипЛаб DeconvNet Сегнет PSPNet Маска-RCNN Вот некоторые из наиболее важных сетей. Нижеследующие обобщены в двух документах. Резюме относительно всеобъемлющее. Если вам интересно, вы можете прочитать соответствующий исходный текст.
Рисунок из: Zhang Jikai, Zhao Jun, Zhang Ran, Lv Xiaoqi, Nie Junlan, Обзор методов сегментации экземпляров изображений в глубоком обучении [J], Малые микрокомпьютерные системы, 2021, 42 (01): 161-171.
Таблица взята из: Xu Hui, Zhu Yuhua, Zhen Tong, Li Zhihui, Обзор методов семантической сегментации изображений в глубоких нейронных сетях [J], Computer Science and Exploration, 2021, 15(01):47-59.
2 Сегментация изображений на основе глубокого обучения
Существует много сегментаций изображений, основанных на глубоком обучении.Давайте представим простой и распространенный код, чтобы объяснить некоторые процессы сегментации изображений с использованием глубокого обучения, надеясь помочь читателям.
2.1 Введение в набор данных Oxford-IIIT Pet
Набор данных, который будет использоваться в этом руководстве, — это набор данных Oxford-IIIT Pet, созданный Parkhi et al. Набор данных состоит из изображений, меток, соответствующих изображениям, и масок, которые помечают пиксели один за другим. Маска на самом деле является меткой для каждого пикселя. Каждый пиксель принадлежит к одной из следующих трех категорий: Категория 1: Пиксели являются частью питомца.
Категория 2: Пиксели — это очертания питомцев.
Категория 3: Ни один из вышеперечисленных/периферийных пикселей.
pip install -q git+https://github.com/tensorflow/examples.git
import tensorflow as tf
from tensorflow_examples.models.pix2pix import pix2pix
import tensorflow_datasets as tfds
tfds.disable_progress_bar()
from IPython.display import clear_output
import matplotlib.pyplot as plt
2.2 Загрузка набора данных Oxford-IIIT Pet
Этот набор данных уже интегрирован в наборы данных Tensorflow, просто загрузите его. Маски сегментации изображения были добавлены только в версии 3.0.0, поэтому мы выбрали именно эту версию.
dataset, info = tfds.load('oxford_iiit_pet:3.*.*', with_info=True)
В приведенном ниже коде выполняется простое увеличение переворота изображения. Затем нормализуйте изображение до [0,1]. Наконец, как упоминалось выше, пиксели помечаются как один из {1, 2, 3} в маске сегментации изображения. Для удобства мы уменьшили маски сегментации на 1, получив следующие метки: {0, 1, 2}.
def normalize(input_image, input_mask):
input_image = tf.cast(input_image, tf.float32) / 255.0
input_mask -= 1
return input_image, input_mask
@tf.function
def load_image_train(datapoint):
input_image = tf.image.resize(datapoint['image'], (128, 128))
input_mask = tf.image.resize(datapoint['segmentation_mask'], (128, 128))
if tf.random.uniform(()) > 0.5:
input_image = tf.image.flip_left_right(input_image)
input_mask = tf.image.flip_left_right(input_mask)
input_image, input_mask = normalize(input_image, input_mask)
return input_image, input_mask
def load_image_test(datapoint):
input_image = tf.image.resize(datapoint['image'], (128, 128))
input_mask = tf.image.resize(datapoint['segmentation_mask'], (128, 128))
input_image, input_mask = normalize(input_image, input_mask)
return input_image, input_mask
Набор данных уже содержит необходимые тестовые и тренировочные сплиты, поэтому мы продолжаем использовать те же сплиты.
TRAIN_LENGTH = info.splits['train'].num_examples
BATCH_SIZE = 64
BUFFER_SIZE = 1000
STEPS_PER_EPOCH = TRAIN_LENGTH // BATCH_SIZE
train = dataset['train'].map(load_image_train, num_parallel_calls=tf.data.experimental.AUTOTUNE)
test = dataset['test'].map(load_image_test)
train_dataset = train.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()
train_dataset = train_dataset.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
test_dataset = test.batch(BATCH_SIZE)
Давайте посмотрим на пример изображения в наборе данных и соответствующей ему маски.
def display(display_list):
plt.figure(figsize=(15, 15))
title = ['Input Image', 'True Mask', 'Predicted Mask']
for i in range(len(display_list)):
plt.subplot(1, len(display_list), i+1)
plt.title(title[i])
plt.imshow(tf.keras.preprocessing.image.array_to_img(display_list[i]))
plt.axis('off')
plt.show()
for image, mask in train.take(1):
sample_image, sample_mask = image, mask
display([sample_image, sample_mask])
2.3 Определение модели
Используемая здесь модель представляет собой модифицированную U-Net. U-Net состоит из кодера (понижающего дискретизатора) и декодера (апсемплера). Чтобы изучить надежные функции при уменьшении количества обучаемых параметров, в качестве кодировщика можно использовать предварительно обученную модель. Поэтому кодировщик в этой задаче будет использовать предварительно обученную модель MobileNetV2, чьи промежуточные выходные значения будут использоваться. Декодер будет использовать модуль повышения частоты дискретизации, реализованный в руководстве Pix2pix в примерах TensorFlow. Количество выходных каналов равно 3, потому что у каждого пикселя есть три возможных метки. Думайте об этом как о многоклассовой классификации, где каждый пиксель будет классифицироваться по трем классам.
OUTPUT_CHANNELS = 3
Как упоминалось ранее, кодировщик представляет собой предварительно обученную модель MobileNetV2, готовую к использованию в tf.keras.applications. Кодер содержит некоторые конкретные выходные данные из средних слоев модели. Обратите внимание, что кодер не обучается во время обучения модели.
base_model = tf.keras.applications.MobileNetV2(input_shape=[128, 128, 3], include_top=False)
# 使用这些层的激活设置
layer_names = [
'block_1_expand_relu', # 64x64
'block_3_expand_relu', # 32x32
'block_6_expand_relu', # 16x16
'block_13_expand_relu', # 8x8
'block_16_project', # 4x4
]
layers = [base_model.get_layer(name).output for name in layer_names]
# 创建特征提取模型
down_stack = tf.keras.Model(inputs=base_model.input, outputs=layers)
down_stack.trainable = False
Downloading data from storage.Google APIs.com/tensorflow/… 9412608/9406464 [==============================] - 0s 0us/step
Декодер/апсемплер — это простая серия модулей повышения дискретизации, которые были реализованы в примерах TensorFlow.
up_stack = [
pix2pix.upsample(512, 3), # 4x4 -> 8x8
pix2pix.upsample(256, 3), # 8x8 -> 16x16
pix2pix.upsample(128, 3), # 16x16 -> 32x32
pix2pix.upsample(64, 3), # 32x32 -> 64x64
]
def unet_model(output_channels):
inputs = tf.keras.layers.Input(shape=[128, 128, 3])
x = inputs
# 在模型中降频取样
skips = down_stack(x)
x = skips[-1]
skips = reversed(skips[:-1])
# 升频取样然后建立跳跃连接
for up, skip in zip(up_stack, skips):
x = up(x)
concat = tf.keras.layers.Concatenate()
x = concat([x, skip])
# 这是模型的最后一层
last = tf.keras.layers.Conv2DTranspose(
output_channels, 3, strides=2,
padding='same') #64x64 -> 128x128
x = last(x)
return tf.keras.Model(inputs=inputs, outputs=x)
2.4 Обучение модели
Теперь осталось только скомпилировать и обучить модель. Используемая здесь функция потерь — loss.sparse_categorical_crossentropy. Эта функция потерь используется, потому что нейронная сеть пытается присвоить метку каждому пикселю, как и при мультиклассовом прогнозировании. В правильной маске сегментации значение каждого пикселя равно одному из {0,1,2}. При этом нейронная сеть также выводит три канала. По сути, каждый канал пытается научиться предсказывать категорию, и в этом случае рекомендуется функция потерь loss.sparse_categorical_crossentropy. В соответствии с выходным значением нейронной сети метка, присвоенная каждому пикселю, представляет собой класс, представленный каналом с наибольшим выходным значением. Это то, что делает функция create_mask.
model = unet_model(OUTPUT_CHANNELS)
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
Давайте попробуем запустить модель и посмотрим, какие прогнозы она дает перед обучением.
def create_mask(pred_mask):
pred_mask = tf.argmax(pred_mask, axis=-1)
pred_mask = pred_mask[..., tf.newaxis]
return pred_mask[0]
def show_predictions(dataset=None, num=1):
if dataset:
for image, mask in dataset.take(num):
pred_mask = model.predict(image)
display([image[0], mask[0], create_mask(pred_mask)])
else:
display([sample_image, sample_mask,
create_mask(model.predict(sample_image[tf.newaxis, ...]))])
show_predictions()
Посмотрим, как модель улучшится при обучении. Для этой цели ниже будет определена функция обратного вызова.
class DisplayCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs=None):
clear_output(wait=True)
show_predictions()
print ('\nSample Prediction after epoch {}\n'.format(epoch+1))
EPOCHS = 20
VAL_SUBSPLITS = 5
VALIDATION_STEPS = info.splits['test'].num_examples//BATCH_SIZE//VAL_SUBSPLITS
model_history = model.fit(train_dataset, epochs=EPOCHS,
steps_per_epoch=STEPS_PER_EPOCH,
validation_steps=VALIDATION_STEPS,
validation_data=test_dataset,
callbacks=[DisplayCallback()])
Sample Prediction after epoch 20 57/57 [==============================] - 3s 54ms/step - loss: 0.1308 - accuracy: 0.9401 - val_loss: 0.3246 - val_accuracy: 0.8903
loss = model_history.history['loss']
val_loss = model_history.history['val_loss']
epochs = range(EPOCHS)
plt.figure()
plt.plot(epochs, loss, 'r', label='Training loss')
plt.plot(epochs, val_loss, 'bo', label='Validation loss')
plt.title('Training and Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss Value')
plt.ylim([0, 1])
plt.legend()
plt.show()
2.5 Предсказание модели
Сделаем несколько прогнозов. Для экономии времени здесь используется только небольшое количество эпох, но вы можете установить большее число для более точных результатов.
show_predictions(test_dataset, 2)
Пока что сегодняшний обмен закончен.Я надеюсь, что с помощью вышеупомянутого обмена вы сможете изучить основной процесс и основной процесс сегментации изображения. Настоятельно рекомендуется, чтобы новички могли выполнять описанные выше шаги, чтобы практиковаться шаг за шагом, и они будут иметь успех.
Сегодняшняя статья взята из:
тензорный поток.Google.can/tutorials/can…
Новички могут ознакомиться с этим веб-сайтом, он очень простой и подходит для новичков.
Конечно, эти два сайта также рекомендуются здесь:
тензорный поток.Google.can/tutorials/can…
keras.io/zh/Я Yufeng, общедоступный номер: кодовое слово Yufeng, добро пожаловать дразнить.
Всем привет, я Ю Фэн, непрофессиональный программист, который пришел в Дачан из мечты Шуанфэя и, наконец, исполнил свое желание. Сейчас работает инженером-алгоритмом на большом заводе. В период обучения в бакалавриате и аспирантуре он посвятил себя участию в различных конкурсах научных исследований, от новичка до чемпиона страны. Во время учебы в аспирантуре я отправился в Университет Цинхуа, чтобы учиться, семь патентов на изобретения, три научно-исследовательские статьи, добро пожаловать, чтобы обратить внимание на общедоступный аккаунт «Кодовое слово Юйфэн», мы будем учиться и развиваться вместе. В этом официальном аккаунте одна за другой будут публиковаться некоторые статьи о программировании и научных исследованиях, так что следите за обновлениями. В то же время я также являюсь владельцем станции B up: кодовые слова Yufeng, ежедневный обмен техническими видео, добро пожаловать на просмотр.