Размытие — это нерезкая область изображения, вызванная движением камеры или объекта, неточной фокусировкой или использованием диафрагмы, обеспечивающей малую глубину резкости. Это приводит к уменьшению разрешения изображения, делая контуры и особенности изображения нечеткими. Таким образом, чтобы получить более четкое изображение, мы можем либо переснять ту же фотографию с предпочтительным фокусом объектива камеры, либо использовать наши знания о глубоком обучении и воспроизвести размытое изображение. Поскольку мой опыт не связан с фотографией, я могу помочь вам очистить ваши изображения с помощью методов глубокого обучения!
Это руководство не для начинающих. Вы должны знать основные концепции глубокого обучения, такие как нейронные сети, CNN, прежде чем начинать этот проект. Также будьте немного знакомы с Keras, Tensorflow и OpenCV.
Существуют различные типы размытия — размытие в движении, размытие по Гауссу, среднее размытие и т. д., но мы сосредоточимся на удалении размытия Размытие по Гауссу изображений. В этом типе размытия веса пикселей неодинаковы. Размытие сильное в центре и уменьшается по краям по кривой в форме колокола.
Набор данных
Прежде чем приступить к работе с кодом, я бы посоветовал вам сначала получить набор данных, состоящий из двух наборов изображений — размытых и чистых изображений. Если вы не найдете доступных ранее существующих наборов данных, вы также можете создать набор данных самостоятельно.
Код
Теперь, когда у нас есть готовый набор данных, мы можем приступить к работе с кодом. Вы можете написать его в своем блокноте Jupyter, Google Colab или любой другой платформе, которая вам нравится. Я использовал Google Colab для этого проекта, так как мне было проще использовать набор данных, связав с ним свой Google Диск.
Импорт зависимостей
import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import random import cv2 import os import tensorflow as tf from tqdm import tqdm from google.colab import drive #If you're using Colab and importing the images from the drive
Здесь я импортировал библиотеку tqdm, чтобы помочь мне создать индикаторы выполнения, чтобы я знал, сколько времени потребуется для выполнения определенного блока кода.
Импорт набора данных
drive.mount('/content/drive', force_remount=True)
Используя приведенный выше код, вы можете подключить свой диск Google к блокноту colab, а затем скопировать путь к чистым и размытым изображениям как:
good_frames = '/content/drive/MyDrive/mini_clean' bad_frames = '/content/drive/MyDrive/mini_blur'
Теперь создайте по 2 списка для чистых и размытых изображений каждый. Мы будем использовать библиотеки предварительной обработки keras для преобразования изображения из расширений «.jpg», «jpeg» или «.png» в массив и добавления их в наши вновь созданные списки. Я выбираю размер изображения 128x128.
clean_frames = [] for file in tqdm(sorted(os.listdir(good_frames))): if any(extension in file for extension in ['.jpg', 'jpeg', '.png']): image = tf.keras.preprocessing.image.load_img(good_frames + '/' + file, target_size=(128,128)) image = tf.keras.preprocessing.image.img_to_array(image).astype('float32') / 255 clean_frames.append(image) clean_frames = np.array(clean_frames) blurry_frames = [] for file in tqdm(sorted(os.listdir(bad_frames))): if any(extension in file for extension in ['.jpg', 'jpeg', '.png']): image = tf.keras.preprocessing.image.load_img(bad_frames + '/' + file, target_size=(128,128)) image = tf.keras.preprocessing.image.img_to_array(image).astype('float32') / 255 blurry_frames.append(image) blurry_frames = np.array(blurry_frames)
Импорт библиотек для модели
from keras.layers import Dense, Input from keras.layers import Conv2D, Flatten from keras.layers import Reshape, Conv2DTranspose from keras.models import Model from keras.callbacks import ReduceLROnPlateau, ModelCheckpoint from keras.utils.vis_utils import plot_model from keras import backend as K seed = 21 random.seed = seed np.random.seed = seed
Разделение набора данных на обучающие и тестовые наборы
Теперь мы разделим основной набор данных на 2 — обучающий и тестовый наборы данных. Я буду делить их в пропорции 80:20, вы можете попробовать и любую другую.
X = clean_frames; y = blurry_frames; from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
Проверка формы поезда и тестовых наборов данных
print(X_train[0].shape) print(y_train[0].shape)
r = random.randint(0, len(clean_frames)-1) print(r) fig = plt.figure() fig.subplots_adjust(hspace=0.1, wspace=0.2) ax = fig.add_subplot(1, 2, 1) ax.imshow(clean_frames[r]) ax = fig.add_subplot(1, 2, 2) ax.imshow(blurry_frames[r])
Вы можете проверить изображения из поезда и тестовых наборов данных с помощью приведенного выше кода, вывод будет таким:
Затем мы можем инициализировать несколько параметров, чтобы использовать их при кодировании нашей модели.
# Network Parameters input_shape = (128, 128, 3) batch_size = 32 kernel_size = 3 latent_dim = 256 # Encoder/Decoder number of CNN layers and filters per layer layer_filters = [64, 128, 256]
Построение модели кодировщика
Если вы не имеете большого представления об автоэнкодерах, не волнуйтесь, вы можете перейти по этой ссылке, чтобы получить общее представление.
inputs = Input(shape = input_shape, name = 'encoder_input') x = inputs
Мы будем напрямую использовать библиотеки, чтобы избежать громоздких ручных вычислений. Мы будем строить стек Conv2D(64) - Conv2D(128) - Conv2D(256). Модель будет иметь входную форму (128, 128, 3) и размер ядра, равный 3, и кодировщик сожмет эту форму до (16, 16, 256) и дополнительно сгладит ее в одномерный массив, который будет вход для нашего декодера.
for filters in layer_filters: x = Conv2D(filters=filters, kernel_size=kernel_size, strides=2, activation='relu', padding='same')(x) shape = K.int_shape(x) x = Flatten()(x) latent = Dense(latent_dim, name='latent_vector')(x)
K.int_shape() здесь помогает преобразовать тензор в кортеж целых чисел.
Создание экземпляра модели кодировщика,
encoder = Model(inputs, latent, name='encoder') encoder.summary()
Построение модели декодера
Модель декодера будет похожа на модель кодера, но будет выполнять обратные или противоположные вычисления. Сначала мы вручную преобразуем одномерный массив из модели кодировщика в форму (16, 16, 256), а затем отправим его в декодер для декодирования обратно в форму (128, 128, 3). Таким образом, стек здесь будет Conv2DTranspose (256) — Conv2DTranspose (128) — Conv2DTranspose (64).
latent_inputs = Input(shape=(latent_dim,), name='decoder_input') x = Dense(shape[1]*shape[2]*shape[3])(latent_inputs) x = Reshape((shape[1], shape[2], shape[3]))(x) for filters in layer_filters[::-1]: x = Conv2DTranspose(filters=filters, kernel_size=kernel_size, strides=2, activation='relu', padding='same')(x) outputs = Conv2DTranspose(filters=3, kernel_size=kernel_size, activation='sigmoid', padding='same', name='decoder_output')(x)
Создание модели декодера,
decoder = Model(latent_inputs, outputs, name='decoder') decoder.summary()
Построение модели автоэнкодера
Теперь, когда у нас есть модели кодера и декодера, мы можем объединить их, чтобы, наконец, построить нашу модель автоэнкодера.
Модель автоэнкодера = модель кодировщика + модель декодера
Создание экземпляра модели автоэнкодера,
autoencoder = Model(inputs, decoder(encoder(inputs)), name='autoencoder') autoencoder.summary()
Последнее, но немаловажное
Перед обучением нашей модели осталось сделать еще одну вещь — выбрать гиперпараметры.
autoencoder.compile(loss='mse', optimizer='adam',metrics=["acc"])
Я выбираю функцию потерь в качестве среднеквадратичной ошибки, оптимизатора в качестве Адама и метрики оценки в качестве точности.
Теперь определяем редуктор скорости обучения, чтобы уменьшить скорость обучения, если метрика не улучшилась,
lr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1), cooldown=0, patience=5, verbose=1, min_lr=0.5e-6)
Называя это в каждую эпоху,
callbacks = [lr_reducer]
Обучение модели
history = autoencoder.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=100, batch_size=batch_size, callbacks=callbacks)
После запуска этого кода точность составила 78,07%.
Конечный результат
Теперь, когда мы успешно обучили нашу модель, давайте посмотрим на прогнозы нашей модели.
print("\n Input Ground Truth Predicted Value") for i in range(3): r = random.randint(0, len(clean_frames)-1) x, y = blurry_frames[r],clean_frames[r] x_inp = x.reshape(1,128,128,3) result = autoencoder.predict(x_inp) result = result.reshape(128,128,3) fig = plt.figure(figsize=(12,10)) fig.subplots_adjust(hspace=0.1, wspace=0.2) ax = fig.add_subplot(1, 3, 1) ax.imshow(x) ax = fig.add_subplot(1, 3, 2) ax.imshow(y) ax = fig.add_subplot(1, 3, 3) plt.imshow(result)
Выход для этого будет,
Таким образом, мы видим, что модель довольно хорошо справилась с устранением размытости изображений и почти смогла восстановить исходные изображения. Мы можем дополнительно оптимизировать наше решение путем настройки гиперпараметров, что может повысить точность модели. Для этого мы можем построить графики функции потерь и точности, чтобы иметь возможность принимать более обоснованные решения.
Для функции потерь
plt.figure(figsize=(12,8)) plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.legend(['Train', 'Test']) plt.xlabel('Epoch') plt.ylabel('Loss') plt.xticks(np.arange(0, 101, 25)) plt.show()
Из этого мы видим, что потери значительно уменьшались, а затем начали стагнировать примерно с 80-й эпохи.
Теперь о точности
plt.figure(figsize=(12,8)) plt.plot(history.history['acc']) plt.plot(history.history['val_acc']) plt.legend(['Train', 'Test']) plt.xlabel('Epoch') plt.ylabel('Accuracy') plt.xticks(np.arange(0, 101, 25)) plt.show()
Из этого мы видим, что точность значительно увеличилась, и она могла бы увеличиться еще больше, если бы было больше эпох. Таким образом, вы можете попробовать увеличить размер эпохи и проверить, действительно ли точность улучшается или нет.
Заключение и будущая работа
Мы подошли к концу этой статьи, но это не конец, этот проект можно было бы улучшить за счет:
- Получение большего количества данных для повышения точности модели
- Настройка гиперпараметров
- Подробное изучение проблем переобучения
Спасибо, что дочитали до сюда, и дайте мне знать, если у вас есть какие-либо отзывы!
Ссылки
https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.303.227&rep=rep1&type=pdf