Это расширенная версия моей публикации на Medium Недавно я сидел в баре с другом зашел разговор о том, в каких задачах в принципе может быть эффективен нейросетевой подход, а где они совершенно излишни. Один класс примеров, где нейросети часто на голову превосходят классические алгоритмы - обработка изображений. Точность решения задачи распознования объектов на изображении может даже превосходить человеческое восприятие. Кроме того, интересны и задачи переноса стиля, генерации реалистичных изображений, superresolution итд. Нейросети могут быть очень эффективны также в задачах типа pixtopix, когда происходит генерация одного изображения из другого. Тогда у меня и возникла идея попробовать применить данные алгоритмы для преобразования 2d фильмов в 3d.  Технология создания стереоскопических 3д фильмов насчитывает около 100 лет  - больше чем истории записи совмещенных звуковых и видео дорожек. Однако из-за требований к оборудованию для воспроизведения и наличия специальных очков для просмотра, стереоскопические фильмы до сих пор не являются стандартом для съемок. С появлением дешевых очков виртуальной реальности может возникнуть соблазн пересмотреть любимые фильмы в 3д. Однако для создания стереоскопического фильма используются 2 видеокамеры, расположенные на расстоянии около 6.5 см снимающие 2 видео одновременно. Для качественной конвертации старых фильмов в 3д и показа их в кинотеатре необходима ручная работа большого количества художников для разметки сцены и ручной отрисовки большинства кадров для другого глаза. Данная задача до недавнего времени плохо поддавалась автоматизации из-за отсутствия однозначного решения при восстановлении стереоскопического изображения из монокулярного. Существует несколько проблем, которые плохо поддаются программному алгоритмическому решению. В идеальном случае, для генерации (рендеринга) изображения для глаза необходимо знание о пространственном расположении всех объектов, видимых глазом. Задача определить расстояние до объекта при помощи одного глаза является невыполнимой из-за недостатка данных. Преимущество бинокулярного зрения именно в том, что параллакс  можно использовать для оценки дальности до объекта. Тем не менее, если человек закроет глаз, он может легко сказать, далеко или близко находится какой-либо объект. Определение дальности до объекта при монокулярном зрении возможно при получении информации о фокусном расстоянии и напряжению мышц, управляющих хрусталиком (глаз всегда сфокусирован либо на объектах вблизи, либо вдали). У близоруких и дальнозорких людей нарушена способность фокусироваться на далеких и близких объектах. Если же человеку дать фото , снятое при помощи фотоаппарата с фиксированным, но неизвестным фокусным расстоянием, принципиально невозможно определить далеко или близко находится изображенный объект от камеры. Съемка фото при помощи фото с большой глубиной резкости позволяет обмануть наш мозг относительно расстояния и размеров объектов или даже об относительных размерах объектов. Однако если человека не пытаются намеренно обмануть, то можно оценить дальность и относительные расстояния исходя из нашего опыта и представления о стандартных размерах видимых объектов и перспективе. Человеческий мозг сам определяет, что если видимый размер дерева меньше, чем человек то скорее всего мы имеем дело с человеком вдали. Именно эта способность необходима для создания кадров для второго глаза из монокулярных изображений.  Вторая существенная проблема — при создании кадра часто нужна отсутствующая информация.   Даже если мы получим информацию, что видит правый глаз на картинке, из нее нельзя восстановить, что видит левый глаз — в изображении доски нет никакой информации о том, что же за забором. В большинстве случаев, тем не менее, картинки бывают схожими и единственная неопределенность возникает, когда близко расположенные объекты закрывают различные части фона для правого и левого глаза. Художникам необходимо догадываться, что находится в некоторых областях, невидимых одним глазом. К счастью, в фильмах обычно все важное и существенное показывают а закрытые части от заднего плана мало отличаются от фона. Две задачи — определение расстояния до видимых объектов и отрисовка невидимых областей затрудняют автоматизацию. Однако обе эти задачи выглядят достаточно простыми для решения при помощи сверточных нейросетей. Задача определения дальности объектов из монокулярных изображений нужна для разработки беспилотных автомобилей, поэтому существуют готовые решения и нейросети, приемлемо ее решающие. Так как построение карты глубин, а это важная часть задачи генерации изображения для левого глаза из изображения для правого глаза решена, можно использовать вышеназванную предобученную сеть как часть своего решения (такой подход называется transfer learning) Я приобрел дешевые 3d очки системы google cardboard для небольших экспериментов с vr. Одна из возможностей их использования мне показалась особенно привлекательной - смотреть стереоскопические изображения и видео.  В качестве обучающего и валидационного датасета были использованы кадры из пары десятков скачанных с торрентов легально приобретенных 3D фильмов и мультфильмов. Для предотвращения переобучения модели использовался каждый 200й кадр, что исключало почти идентичные кадры из рассмотрения. Часто стереоскопические фильмы храняться в том же формате, что и обычные фильмы с особой меткой в метаданных и изображением, состоящим из 2х частей - для правого и левого глаза. Форматы стереовидео называются OverUnder, Side-by-Side. Чаще всего в видео OverUnder изображения для левого глаза находится над изображением для правого глаза, хотя редко встречается и противоположная ситуация. В некоторых вариантах формата изображение сжато в два раза по одной из осей. Такого типа видео легко интерпретируются большинством видеопроигрывателей. Подготовим нарезку верхних и нижних кадров для обучения и положим их в папки Uf и Df: После конвертации нескольких фильмов в папке Uf находятся кадры для правого глаза, Df для левого глаза. Также для такого рода задач важна информация о геометрическом положении пикселей. Учет положения пикселей может быть реализован в слое CoordConv - слое, добавляющем координаты пикселя. Идея CoordConv может также быть реализована путем генерации input - канала, содержащего координаты пикселей (корректно заставить работать CoordConv на фреймворке keras оказалось трудозатратно). Создадим генератор изображений для обучения: Я использовал end-to-end модель без добавления знаний о геометрии мира и расположении глаз. После нескольких попыток, была выбрана следующая архитектура (очень постарался, чтоб нарисовать,но многие детали все равно не очень подробны):      Из особенностей, специфичных для задачи можно выделить 1. Использование предобученной сети для определения дальности до объектов (отличные результаты были получены тут https://github.com/ialhashim/DenseDepth ). Выход нейросети был нормирован для ускорения дальнейшего обучения. 2. Использования Skip-connections — кадр для правого глаза должен быть похож на кадр для левого глаза 3. Использование информации о геометрическом положении пикселя (обычно бывает реализовано в виде CoordConv слоя [https://arxiv.org/pdf/1807.03247.pdf ], я просто добавил 2 входных канала с использованием numpy, что эквивалентно) 4. Использование фильтров, в свертках последних Residual блоков вытянутых горизонтально — связано с тем, что основные искажения — горизонтальные смещения некоторых объектов. Эксперименты показали, что использование в качестве функции потерь попиксельного среденеквадратичного или среднемодульного отклонения приводит к размыванию и низкому качеству изображения. Поэтому в качестве функции потерь использовалась линейная комбинация mse, structural similarity loss (это  функция оценки схожести изображений, включающая в себя схожесть контрастности изображений) и loss, основанный на низкоуровневых признаках, извлеченных при помощи нейросети VGG16.   Загрузим предобученную DenseDepth модель и добавим слои для генерации изображения для другого глаза: (что лежит в custom_objects можно посмотреть на гитхабе или kaggle). Предобученная модель nyu.h5 взята отсюда  Сохраняем промежуточные результаты в чекпоинт и запустим обучение (делал это в облаке kaggle): В результате была получена нейросеть, генерирующая изображение из монокулярного.  Для проверки качества работы удобно создавать гифки, подобные той, что в заголовке - периодически меняем 2 изображения и видим, что возникает ощущение взгляда "под другим углом". Для этого создадим функцию создания анимированных gif из картинки: Результат: Видим, что на gif изображениях ощущения объема достаточно реалистичное. Попробуем перекодировать фильм, изначально выпущенный в 2d. Для этого сконвертируем каждый кадр и добавим его в новом видео (к сожалению ютуб поддерживает только формат side-by-side): К сожалению, скорость конвертации далека от реального времени (на моем ноутбуке с gtx1060 3gb) 1 кадр кодируется от 100мс до 1 с в зависимости от разрешения. Есть надежда, что более мощные gpu позволят сделать 3d - видеоплеер с конвертацией в реальном времени. К сохраненному видео можно добавить звук и флаги метаинформации при помощи утилиты ffmpeg:  Так как GPU есть не у всех, готовую предобученную сеть можно запустить в googleColab, выделяющей каждому юзеру виртуальную машину с gpu ускорителем . Я попытался сделать относительно простой интерфейс. Для запуска следует нажать run и загрузить ваше видео. Конвертация обычно занимает около 1 с на 1 кадр при разрешении по умолчанию. После нее видео скачается на ваш компьютер. Для того, чтобы оценить работу сети по конвертации фильмов, я сконвертировал несколько из них и приобрел недорогие 3d очки для смартфона. Для просмотра использовалось приложение1 приложение2 и приложение3. По результатам субъективного опыта могу сказать, что эффект объема действительно присутствует и серьезных артефактов, мешающих просмотру не наблюдается. Однако сгенерированное изображение для левого глаза оказывается немного размытым, поэтому при просмотре может возникнуть ощущение, что просело зрение на одном глазу (сказано другом, который проверял видео и немного испугался, что глаз стал хуже видеть).  К сожалению, youtube плохо отображает стереоскопические видео на различных устройствах. Поэтому примеры некоторые конвертированные видео показаны в режиме стереопары для красно-синих очков. Для примера также одно видео конвертировано без добавления метаданных о типе стереопары (отображается в youtube как Sidebyside видео) Спасибо всем, кто дочитал досюда. Вот ссылка на googleColab для преобразования ваших 2D-видео в 3D. Также буду рад вашим предложениям по повышению качества конвертера (не хотелось бы сильно усложнять модель при этом). Конвертированные видео можно просматривать с помощью любых 3d мониторов/TV и VR-шлемов в том числе GoogleCardboard