Этот проект основан на исследовательской работе, разработанной в Калифорнийском университете в Беркли Ричардом Чжаном, Филиппом Изолой и Алексеем А. Эфросом. Оригинал - Colorful Image Colorization.
Общее
Идея этого урока будет заключаться в разработке полностью автоматического подхода, который будет генерировать реалистичные цвета в черно-белых (B & W) фотографиях и видео. В оригинальной статье, авторы приняли глубинную неопределенность проблемы, представив ее в качестве задачи классификации с использованием классовой балансировки во время обучения для увеличения разнообразия цветов в результате. Подход искусственного интеллекта (ИИ) реализован в виде прямого прохода в СНС ("Свёрточная Нейронная Сеть") / CNN (" Convolutional Neural Network") во время тестирования и обучен работе с более чем миллионом цветных изображений.
Вот фотокарточка 1906 года, на которой показано одно из первых испытаний самолета Сантоса Дюмона "14-бис" в Париже:
И его цветная версия с использованием моделей, разработанных с использованием этой техники искусственного интеллекта:
Такая же техника может быть применена к старым видеозаписям. Здесь видеозапись черно-белой съемки города Рио-де-Жанейро, Бразилия, 1932 года:
И этаже версия, но уже в цвете:
Шаг 1: Lab Цветового Пространства
Обычно мы привыкли кодировать цветные фотографии с помощью модели RGB. Цветовая модель RGB является разновидностью цветовой модели, в которой красный, зеленый и синий свет суммируются различными способами для получения широкого спектра цветов. Название модели происходит от инициалов трех основных добавочных цветов: красного, зеленого, и синего. (red, green, blue)
Но моделью, которая будет использоваться в этом проекте, является "Lab.
Цветовое пространство CIELAB (также известное как CIE L*a*b* или иногда сокращенно просто "Lab" цветового пространства) - это цветовое пространство, определенное Международной комиссией по освещению (CIE) в 1976 году. Он выражает цвет как три числовых значения: L* для яркости и a* и b* для зелено-красных и сине-желтых компонентов цвета.
Цветовое пространство L * a * b * * было создано по теории противоположных цветов, где два цвета не могут быть одновременно зелеными и красными, или желтыми и синими. CIELAB был разработан таким образом, чтобы быть концептуально единообразным по отношению к цветовому зрению человека, означая, что одинаковое количество числовых изменений в этих значениях соответствует примерно такому же количеству визуально воспринимаемых изменений.
В отличие от цветовой модели RGB, цвет Lab предназначен для соответсвия человеческому зрению. Она стремится к единообразию восприятия, а ее L-компонент тесно связан с восприятием человека. Компонент L является именно тем, что используется в качестве входных данных для модели ИИ, то есть для оценки оставшихся компонентов "a" и "b".
Шаг 2: Процесс ИИ (Глубокое Обучение)
Как было отмечено во введении, подход искусственного интеллекта (ИИ) реализован в виде прямого прохода в СНС ("Свёрточная Нейронная Сеть") во время тестирования и обучен работе с более чем миллионом цветных изображений. Другими словами, миллионы цветных фотографий были разложены с помощью Lab-модели и использованы в качестве входных параметров ("L") и классификационных меток ("a" и "b"). Для простоты разделимся на две части: "L" и "a+b", как показано на блок-схеме:
Имея тренированную модель (общедоступную), мы можем использовать ее для окрашивания новой черно-белой фотографии, где эта фотография будет являться входом в модель или компонентом "L". Выводом модели будут другие компоненты "a" и "b", которые после добавления к оригиналу "L", будут возвращать полноцветную фотографию, как показано здесь:
Короче говоря, используя широкий и разнообразный набор объектов и сценических данных, состоящий из 1,3-миллионных фотографий из ImageNet и применяя алгоритм глубокого изучения (Feed-Forward СНС), были созданы и доступны окончательные модели:
Шаг 3: Рабочая среда
Первое, что нужно сделать, это организовать среду, в которой мы будем работать. Давайте создадим папку и назовем её:
- Photo_Video_Colorization
В созданной директорией, давайте создадим вложенные папки:
- Model
- input_images
- input_videos
- colorized_images
- colorized_frames
- colorized_videos
Перейдите в хранилище, и скачайте 3 файла, после чего переместите их в созданную подпапку "/model". Эти файлы:
- colorization_release_v2.caffemodel
- colorization_release_v2_norebal.caffemodel
- colorization_release_v1.caffemodel
Предполагаю, что на вашем компьютере установлены Python (версия 3.6) и OpenCV (4.0). Мы опишем поэтапно весь процесс раскрашивания с помощью Jupyter Notebooks. Я рекомендую вам следовать пошагово по инструкции, но если хотите, Вы можете скачать файлы и тестовые фотографии из моего GitHub, Зеркало.
Я также рекомендую вам ознакомиться с замечательным учебником доктора Эдриан Роузброк "Черно-белые цвета изображения с OpenCV и Глубокое Обучение", который стал руководством для этого проекта.
Шаг 4: Черно-белая окраска фотографий
Каждый из следующих шагов - это отдельная ячейка в Jupyter.:
1. Import important Libraries / Импортируйте важные библиотеки:
import numpy as np
import matplotlib.pyplot as plt
import cv2
2. Define Image to be colorized / Определите цвет раскрашиваемого изображения:
IMAGE = "soldiers_1941"
Примечание: здесь Вы можете использовать любую фотографию. В данном случае, я использую черно-белую фотографию 1941 г. солдат во время Второй мировой войны. Фотография доступна на моем GitHub.
3. Define Model Paths / Определение Путей Моделей:
prototxt = "./model/colorization_deploy_v2.prototxt"
model = "./model/colorization_release_v2.caffemodel"
points = "./model/pts_in_hull.npy"
image = "./input_images/"+IMAGE
4. Load serialized black and white colorizer model and cluster / Загрузить сериализованный черно-белый колорификатор модели и кластер:
net = cv2.dnn.readNetFromCaffe(prototxt, model)
pts = np.load(points)
5. Add the cluster centers as 1x1 convolutions to the model / Добавьте к модели кластерные центры в виде сверток 1x1:
class8 = net.getLayerId("class8_ab")
conv8 = net.getLayerId("conv8_313_rh")
pts = pts.transpose().reshape(2, 313, 1, 1)
net.getLayer(class8).blobs = [pts.astype("float32")]
net.getLayer(conv8).blobs = [np.full([1, 313], 2.606, dtype="float32")]
6. Load the input image, scale it and convert it to Lab / Загрузите входное изображение, масштабируйте его и конвертируйте в Lab:
Обратите внимание, что сначала мы конвертируем изображение в оттенки серого. На этом шаге нет необходимости, но я понимаю, что некоторые черно-белые фотографии, особенно старые, могут подвергаться некоторому на качество изображения в течение многих лет, так что лучше их немного почистить.
image = cv2.imread(image)
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
На данный момент у нас есть исходное изображение, но для того, чтобы показать его прямо на ячейке Jupyter, мы должны использовать библиотеку pyplot:
plt.imshow(image)
plt.axis('off');
7. Extracting "L" / Извлечение “l”:
Теперь возьмем наше "изображение" и перейдем к процессу окрашивания, где сначала нужно перемасштабировать, преобразовав его в Lab, чтобы извлечь компонент "L" и отцентрировать его:
scaled = image.astype("float32") / 255.0
lab = cv2.cvtColor(scaled, cv2.COLOR_RGB2LAB)
resized = cv2.resize(lab, (224, 224))
L = cv2.split(resized)[0]
L -= 50
8. Predicting "a" and "b" / Прогнозирование "a" and "b":
net.setInput(cv2.dnn.blobFromImage(L))
ab = net.forward()[0, :, :, :].transpose((1, 2, 0))
ab = cv2.resize(ab, (image.shape[1], image.shape[0]))
9. Creating a colorized Lab photo (L + a + b) / Создание цветной Lab фотографии (L + a + b):
L = cv2.split(lab)[0]
colorized = np.concatenate((L[:, :, np.newaxis], ab), axis=2)
Так же, как и в случае с полутоновым изображением, давайте проверим, как выглядит окрашенное изображение:
plt.imshow(colorized)
plt.axis('off');
plt.title('colorized LAB image');
Упс, кажется, что изображение Lab не может нам многое расказать, давайте конвертируем его в RGB и посмотрим результат:
10. Converting to RGB / Преобразование в RGB:
colorized = cv2.cvtColor(colorized, cv2.COLOR_LAB2RGB)
colorized = np.clip(colorized, 0, 1)
colorized = (255 * colorized).astype("uint8")
plt.imshow(colorized)
plt.axis('off');
Уау! Довольно удивительно! Это фотография 1941 года, которая, кажется, будто была всегда цветной! Давайте сохраним результат:
11. Saving the final RGB photo / Сохранение результата в формате RGB:
cv2.imwrite("./colorized_images/Color_"+IMAGE, cv2.cvtColor(colorized, cv2.COLOR_RGB2BGR))
Еще один результат: Чарльз Дарвин посетил Рио в 1832 году:
Шаг 5: Окрашивание видео
Как только мы раскрасили фотографии, раскрасить видео - это уже несложная задача. Мы должны следовать следующим общим шагам:
- Получить черно-белые кадры и загрузить их в подкаталог input_video/.
- Читать видео по одному кадру за раз
- Имея один кадр, применить то, что мы сделали для фотографии
- Имея раскрашенный кадр, сохраните его в другой подпапке: colorized_video_frames
- Закрыть окна OpenCv.
Давайте займемся настоящим делом:
Загрузите B_W_Video_Colorization.ipynb Зеркало из моего GitHub.
Первым тестом, который я сделал, был скаченый с Youtube ч/б фильм:
Для этого я использовал бесплатный инструмент: VidPaw.
Применяяя описанные выше шаги, в конце мы сохраним все окрашенные кадры в подпапке colorized_video_frames. Давай сделаем это:
1. Начните с определения файла, который должен быть окрашен (который должен находиться в папке input_video):
VIDEO = "rio_32.mp4"
2. Определение путей, констант и переменных видео:
prototxt = "./model/colorization_deploy_v2.prototxt"
model = "./model/colorization_release_v2.caffemodel"
points = "./model/pts_in_hull.npy"
video = "./input_video/"+VIDEO
width = 500
vs = cv2.VideoCapture(video)
3. Загрузка и подготовка модели:
net = cv2.dnn.readNetFromCaffe(prototxt,model)
pts = np.load(points)
class8 = net.getLayerId("class8_ab")
conv8 = net.getLayerId("conv8_313_rh")
pts = pts.transpose().reshape(2, 313, 1, 1)
net.getLayer(class8).blobs = [pts.astype("float32")]
net.getLayer(conv8).blobs = [np.full([1, 313], 2.606, dtype="float32")]
4. Разделение видео, показ кадр за кадром и применение модель:
count = 0
success = True
while success:
success, frame = vs.read()
if frame is None:
break
frame = imutils.resize(frame, 500)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
scaled = frame.astype("float32") / 255.0
lab = cv2.cvtColor(scaled, cv2.COLOR_RGB2LAB)
resized = cv2.resize(lab, (224, 224))
L = cv2.split(resized)[0]
L -= 50
net.setInput(cv2.dnn.blobFromImage(L))
ab = net.forward()[0, :, :, :].transpose((1, 2, 0))
ab = cv2.resize(ab, (frame.shape[1], frame.shape[0]))
L = cv2.split(lab)[0]
colorized = np.concatenate((L[:, :, np.newaxis], ab), axis=2)
colorized = cv2.cvtColor(colorized, cv2.COLOR_LAB2BGR)
colorized = np.clip(colorized, 0, 1)
colorized = (255 * colorized).astype("uint8")
cv2.imshow("Original", frame)
cv2.imshow("Colorized", colorized)
cv2.imwrite("./colorized_video_frames/frame%d.jpg" % count, colorized)
count += 1
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
vs.release()
cv2.destroyAllWindows()
Вышеуказанный цикл обычно занимает некоторое время. Например, процесс окрашивания этого видео (8 минут), имеющего около 14 000 кадров, занял у меня около 3 часов на MacBook Pro - 2,9 ГГц Core i7 с 16 ГБ 2133 МГц оперативной памяти.
5. После того, как у вас есть файлы с кадрами, вы должны "собрать" его заново, чтобы создать видео. Данная функция может это сделать:
def convert_frames_to_video(pathIn, pathOut, fps):
frame_array = []
files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))]
#for sorting the file names properly
files.sort(key = lambda x: int(x[5:-4]))
for i in range(len(files)):
filename=pathIn + files[i]
#reading each files
img = cv2.imread(filename)
height, width, layers = img.shape
size = (width,height)
print(filename)
#inserting the frames into an image array
frame_array.append(img)
out = cv2.VideoWriter(pathOut,cv2.VideoWriter_fourcc(*'MJPG'), fps, size)
for i in range(len(frame_array)):
# writing to a image array
out.write(frame_array[i])
out.release()
Обратите внимание, что в зависимости от того, какой Video Controler установлен на вашем компьютере, кодек (*'MJPG') должен быть изменен. Пожалуйста, ознакомьтесь с документацией OpenCV. В конце концов, это был бы опыт "проб и ошибок".
Теперь он применяется только для того, чтобы применить функцию на окрашенных кадрах:
pathIn= './colorized_video_frames/'
pathOut = './colorized_videos/color_rio_32.avi'
fps = 30.0
convert_frames_to_video(pathIn, pathOut, fps)
Полученное "сырое" видео можно посмотреть здесь:
Обратите внимание, что видео, не имеет звука. Я это вытащил оригинальный звук из черно-белых фильмов и добавил его к окрашенному, используя iMovie. Результат здесь:
Шаг 7: Итог
Как всегда, я надеюсь, что этот проект поможет другим найти свой путь в захватывающий мир технологий!
Для получения подробностей и окончательного кода, пожалуйста, посетите репозиторий GitHub: MJRoBot-Python4DS, Зеркало