Щілинна зйомка: реалізація на bash (ffmpeg + imagemagick)

Не пам'ятаю що і чому я шукав в інтернеті кілька днів тому, але я натрапив на цікаву статтю з незвичайними фотографіями. А пізніше на ще одну статтю, де описувалася реалізація алгоритму створення таких фотографій на python. Після прочитання мене зацікавила ця тема і я вирішив провести вечора травневих свят з користю для себе, а саме реалізувати алгоритм «конвертування відео в щілинне фото. Правда, не на пітоні, але підручними засобами на bash'є. Але про все по порядку.

Що таке щілинне фото
Вид фотографії, на якій зображено не одна подія в один конкретний момент часу, а кілька подій. Це досягається за рахунок того, що щілинна камера знімає кадри шириною в один піксель (це і є «щілина») і «склеює» їх в одне фото. Трохи заплутано звучить і поки складно уявити, що це таке і як виглядає. Самим простим поясненням для мене був коментар до однієї з вищезазначених статей від користувача Stdit:
image
Після цього все стає зрозумілим.

Приклад для наочності:
image

Алгоритм побудови щілинної фотографії
  1. Розкласти відео на безліч зображень.
  2. Обрізати кожне отримане зображення по ширині в один піксел з заданим зміщенням (щілиною).
  3. Зібрати отримане безліч зображень в одне.
Звучить страшно і просто.

Дано
  • Камера Xiaomi Yi
  • Бажання розібратися і зробити кілька незвичайних фото
  • Пару вечорів вільного часу


Рішення
Перше і найпростіше, що спадає на думку, це написати bash скрипт, який буде обробляти відео та фото у відповідності з описаними кроками алгоритму. Для реалізації задуманого мені знадобився ffmpeg і imagemagick. У спрощеному вигляді на псевдо bash скрипт виглядає так:
ffmpeg -i videoFile frame-%d.png

for (i = 1; i < = framesCount; i++));
do
convert -crop 1xframeHeight+slitShift+0 frame-$i.png slit-$i.png
done

montage slit-%d.png[1-framesCount] -tile framesCountx1 -geometry +0+0 outputImage


Розберемося що тут відбувається
  • По-перше, з допомогою утиліти ffmpeg розбиваємо відео на безліч зображень виду frame-0.png...frame-n.png.
  • По-друге, з допомогою утиліти convert з пакунка imagemagick обрізаємо кожне отримане зображення (ключ -crop) наступним чином: ширина == 1px, висота == висоті зображення. Так само вказуємо зміщення щілини по горизонталі. Зберігаємо файли виду slit-0.png...slit-n.png.
  • -третє, з допомогою утиліти montage з пакунка imagemagick збираємо отримані зображення в одне фото. Ключ -tile вказує на те, що всі фото потрібно зібрати в одне за шаблоном «framesCount по горизонталі і 1 по вертикалі», тобто зібрати безліч зображень в один ряд.


Результат
За пару вечорів був написаний скрипт, якому на вхід подаємо відео файл, а на виході отримуємо фотографію. В теорії на вхід можна подавати відео в будь-якому форматі, який підтримує ffmpeg. Вихідний файл можна отримати в тих форматах, які підтримує imagemagick.

Користуватися скриптом дуже просто:
./slitcamera.sh --input=test.avi --output=test.png --slit-shift=100
 

де input — відео файл для обробки, output — назва результуючого файла, slit-shift — зміщення щілини по горизонталі.

Першим ділом для швидкого тестування я не став знімати відео на камеру, а скачав перше-ліпше відео з youtube і «згодував» його скрипту. Ось що з цього вийшло:


На наступний день з собою на прогулянку я взяв свою Xiaomi Yi і зняв кілька відео. Ось що з цього вийшло:

Рідне Азовське море (фото зроблено з відео роздільною здатністю до 1920x1080 пікселів і тривалістю 31 секунду, 60к/с)




А ці фото зібрані відео з роздільною здатністю 1280x720 пікселів і тривалістю 16 секунд, 120к/с. Зверніть увагу на фон другого фото. Він не статичний. На тлі було рухоме колесо огляду.

Переглянути і завантажити скрипт можна в моєму репозиторії на GitHub. Пропозиції, критика і пулреквесты тільки вітаються.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.