В предыдущей статье я подробно рассказывал о своём пайплайне, который автоматически превращает эпизоды в готовые Shorts. Одним из ключевых элементов этой системы стала виртуальная камера — алгоритм автоматического кадрирования, имитирующий работу живого оператора.
На первый взгляд задача проста: из горизонтального видео 16:9 получить вертикальный ролик 9:16, удерживая человека в кадре. Однако при реализации возникает множество инженерных проблем:
- детектор лиц выдаёт шум;
- лицо периодически теряется;
- движение объекта неравномерно;
- простое следование за центром рамки недостаточно;
- слишком точная камера выглядит неестественно.
Чтобы результат не напоминал дёрганый автофокус начала 2010-х, нужна система, которая ведёт себя как настоящий оператор: плавно, с инерцией, с предсказанием движения и композиционными поправками. Даже в отсутствие лиц она должна адекватно вести себя, а не зависать.
В статье разбирается полный алгоритм виртуальной камеры:
- трёхуровневый fallback для детекции лиц: MediaPipe → YuNet → Haar Cascade;
- простой, но эффективный трекинг лица между кадрами;
- антидрожь и low-pass фильтрация сигнала;
- моделирование камеры как демпфированного осциллятора;
- композиционные правила: правило третей, смещение по сторонам, подъём по уровню глаз, поля вокруг лица;
- режим Ken Burns при потере или отсутствии лица;
- интерполяция траектории и применение виртуального кропа.
Почему задача сложнее, чем кажется
Простой кроп по центру не работает: при смещении человека к краю он обрезается, при двух людях — нарушается композиция, при движении — камера либо прыгает, либо отстаёт. Если лицо исчезает, видео становится статичным или бессмысленным.
Поэтому нужна не просто обрезка, а виртуальная камера — сущность с:
- целью наблюдения;
- инерцией;
- ограничениями скорости и ускорения;
- задержкой реакции;
- композиционными правилами;
- fallback-поведением.
Только такой подход создаёт впечатление работы живого оператора.
Архитектура решения
Алгоритм не принимает решение по одному кадру — он живёт во времени. Качество определяется не столько точностью детектора, сколько тем, как система обрабатывает неидеальные данные.
Детекция лиц: трёхуровневый fallback
Любой детектор может ошибаться: терять лицо при повороте, сбиваться на плохом освещении или ломаться на аниме. Поэтому вместо поиска идеального решения строится устойчивая цепочка деградации.
MediaPipe — основной детектор
Работает быстро на CPU, хорошо ловит лицо под углом, возвращает confidence и bounding box в нормализованных координатах. Основной выбор для production.
YuNet — резервный вариант
Используется, когда MediaPipe недоступен или не находит лицо, которое очевидно есть. Медленнее, но работает через ONNX в OpenCV — надёжная вторая линия обороны.
Haar Cascade — последняя надежда
Устаревший, но почти везде доступный детектор без тяжёлых зависимостей. Точность невысока, но он не даёт системе полностью «ослепнуть».
Единый интерфейс
Вся цепочка скрыта за одним API. На выходе — унифицированная структура с центром, размером, confidence и bounding box. Остальная система не знает, какой детектор что нашёл.
Трекинг лица между кадрами
Детектор говорит, что есть на кадре. Но камере нужно знать, за каким объектом следить во времени. Без трекинга при двух лицах или скачках confidence камера будет прыгать.
Простой nearest-neighbor трекинг
На каждом кадре выбирается детекция, ближайшая к позиции лица на предыдущем. Если расстояние в пределах допуска — это тот же объект. Работает хорошо для сцен с ограниченным числом лиц и плавным движением.
Инертный трек при потере лица
Когда лицо временно теряется (поворот, блик, перекрытие), камера не резко переключается, а продолжает верить последней известной позиции в течение короткого grace period. Это убирает нервные дёрганья.
Зачем не нужен сложный трекер
Можно использовать optical flow, Kalman filter или appearance embeddings. Но для вертикального кропа в talking-head сценах простой distance-based подход даёт достаточное качество при минимальной сложности и высокой надёжностью в production.
Стабилизация сигнала: anti-jerk и low-pass фильтр
Даже корректный детектор выдаёт шум: центр бокса дрожит, размер прыгает, появляются ложные уверенные детекции. Если подавать это напрямую в камеру — будет дрожание.
Anti-jerk: жёсткое ограничение скачков
Лицо не может телепортироваться между кадрами. Если детектор сообщает о резком смещении — это шум. Такие прыжки отсекаются на уровне hard clamp.
Low-pass фильтр: сглаживание остаточного шума
Остальные колебания сглаживаются экспоненциальным фильтром: новое значение аккуратно смешивается с предыдущим стабильным.
Зачем оба фильтра
Только anti-jerk не убирает мелкую дрожь. Только low-pass может утянуть камеру за выбросом. Только их комбинация делает сигнал пригодным для физической модели.
Виртуальная камера как физическая система
Мгновенное перемещение камеры выглядит как работа робота. Настоящий оператор обладает инерцией, ограничениями на ускорение и естественным демпфированием. Поэтому камера моделируется как демпфированный осциллятор.
Математическая модель
Используется классическая spring-damper система:
- m — условная масса;
- k — жёсткость пружины;
- c — демпфирование;
- x — текущая позиция;
- x_target — целевая позиция;
- v — скорость.
Пружина тянет камеру к цели, демпфирование гасит колебания, ограничения делают движение правдоподобным.
Численная интеграция
На каждом шаге анализа обновляются скорость и позиция камеры. Схема проста, но даёт полный контроль над динамикой.
Ключевые параметры
Понимание параметров позволяет настраивать поведение:
- follow_stiffness — сила притяжения к цели: выше — быстрее реакция, но риск перерегулирования;
- follow_damping — сопротивление движению: выше — меньше раскачки;
- max_center_accel — лимит ускорения: камера не рвётся резко;
- max_center_speed — лимит скорости;
- velocity_soften — смягчение скорости: меньше высокочастотных колебаний;
- velocity_decay — затухание: камера быстрее успокаивается.
Камера — это не координата, а динамическая система. Это и делает её визуально правдоподобной.
Predictive lead: предсказание движения
Чтобы не отставать от быстро движущегося объекта, камера экстраполирует его траекторию. Это делает следование более «человеческим».
Human lag: искусственная задержка
Иногда полезно немного замедлить реакцию. Микрозадержка имитирует реальную реакцию оператора и улучшает восприятие. Реализм — не всегда максимум точности.
Композиция: камера должна кадрировать красиво
Даже стабильная камера может давать плохой кадр, если композиция примитивна. Постоянное центрирование выглядит «машинно».
Rule-of-thirds и side bias
При нескольких лицах или свободной композиции объект смещается к линиям третей. Смещение адаптивное: если лицо близко к краю, bias ослабевает, чтобы не ухудшить кадр.
Single-face режим
При одном стабильном лице камера работает иначе:
- меньше композиционных изменений;
- больше стабилизации;
- консервативная скорость;
- лучшее удержание talking-head кадра.
Условная настройка параметров — то, что отличает рабочую систему от абстрактного алгоритма.
Eye-level lift
Цель смещается от центра бокса к уровню глаз. Это небольшая поправка, но она сильно улучшает восприятие — камера смотрит не в нос, а в лицо.
Dead zone
Микродвижения и шум детектора не должны вызывать реакцию. Dead zone игнорирует мелкие изменения — без него камера выглядит нервной.
Face margin
Лицо не должно прижиматься к краю. Защитный зазор предотвращает обрезание ушей, волос и жестов, делая кадр «воздушнее».
Ken Burns fallback: когда лица нет
Система не должна зависать, если лицо потеряно или отсутствует. На помощь приходит эффект Кена Бёрнса — плавное панорамирование и зум.
Модель движения
Простейшая реализация — синусоидальные изменения центра и масштаба. Это даёт плавное, предсказуемое движение без рывков.
Зачем Ken Burns
Статичный кроп при отсутствии лица выглядит как ошибка. Ken Burns создаёт ощущение, что камера «держит сцену», и fallback не воспринимается как сбой.
Плавный переход
Переход из режима трекинга в fallback — постепенный. Скорость камеры гасится, а не обнуляется. Такие детали незаметны в коде, но очевидны в результате.
Интерполяция: от дискретных состояний к плавному движению
Анализ может идти с частотой 8 FPS, а видео — 30 или 60 FPS. Без интерполяции движение будет ступенчатым.
Интерполяция траектории
Между точками применяется линейная интерполяция. Этого достаточно, так как физическая модель уже обеспечивает гладкость.
Применение камеры
На каждом кадре:
- берётся исходный кадр;
- извлекаются центр и zoom из интерполированной траектории;
- вычисляется ROI;
- область вырезается;
- масштабируется до 9:16.
На этом этапе модель превращается в готовое видео.
Профиль параметров: operator mode
Качество системы — не в одной формуле, а в балансе параметров. Ниже пример настройки под «живого оператора» для talking-head сценариев.
Разные стили поведения
Система поддерживает профили:
- Static / robotic — почти не двигается;
- Operator mode — живое, но контролируемое движение;
- Fast reaction — быстрая реакция;
- Slow and smooth — медленно и мягко.
Удобно думать не о числах, а о поведении камеры.
Практические edge cases
Лицо под углом или в профиль
Помогает увеличение времени grace period, снижение порогов детекции, подключение YuNet или снижение минимального confidence.
Аниме и нефотореалистичные лица
Проблема — в domain mismatch. Решение: ослабить пороги, уменьшить минимальный размер лица, использовать специализированный детектор.
Несколько лиц
Слишком агрессивный single-face режим вредит. Лучше переключиться на композиционный режим, удерживающий обоих говорящих.
Быстрое движение
Adaptive boost позволяет камере «проснуться» при резких движениях, не делая её гиперактивной в спокойных сценах.
Почему архитектура работает
Сила решения — не в отдельных формулах, а в подходе:
- не полагаться на один компонент, а строить fallback-архитектуру;
- не доверять сырым данным — стабилизировать сигнал;
- моделировать динамику явно — камера как физическая система;
- учитывать восприятие — human lag, eye-level lift, dead zone;
- проектировать деградацию — fallback при отсутствии лиц;
- думать о субъективном качестве, а не только о точности.
Производительность
Стоимость пайплайна:
- N — число анализируемых кадров;
- D — время детекции на кадр;
- P — время трекинга и физики.
Анализ можно удешевить:
- снижать разрешение на этапе детекции;
- уменьшать частоту анализа в спокойных сценах;
- отключать резервные детекторы, если основной работает стабильно.
Эти оптимизации дают наибольший эффект в production.
Итог
Готовый алгоритм:
- не дёргается на шуме детектора;
- не выглядит роботизированным;
- умеет мягко деградировать;
- лучше удерживает talking-head и обычные сцены, чем простой кроп по центру.