Розробка AI для заміни фону у відео
Заміна фону у відео — завдання складніше, ніж у статичних зображеннях: потрібна часова узгодженість між кадрами (temporal coherence), інакше фон буде мерехтіти. Ми реалізуємо системи для відеоконференцій (Zoom, Teams), спортивних трансляцій та новинних студій без хромакею. Realtime-вимоги для конференцій — 15–30 FPS при затримці <50 мс на CPU/GPU з низьким енергоспоживанням.
Чому temporal coherence критична для відео?
Кожен кадр обробляється незалежно, але без врахування попередніх кадрів маска фону може різко змінюватися, створюючи артефакти. Temporal coherence усуває мерехтіння, використовуючи рекурентні нейронні мережі. RVM (Robust Video Matting) — одна з найкращих моделей, яка явно зберігає прихований стан між кадрами. Детальніше про RVM можна прочитати в офіційній документації.
Як ми досягаємо temporal coherence?
Ключове рішення — RVM з рекурентним станом. Модель зберігає приховані вектори між кадрами, що усуває мерехтіння. Наш досвід показує, що цей підхід дає плавну маску навіть на складних сценах з рухом камери. Наприклад, в одному з проєктів для стрімінгової платформи ми впровадили RVM MobileNetV3 — заміна фону працювала на 30 FPS на ноутбуці без GPU.
import torch
import torchvision.transforms as T
from PIL import Image
import numpy as np
import cv2
class VideoBackgroundReplacer:
def __init__(self, model_path: str, device: str = 'cuda'):
self.device = device
# RVM з recurrent state — ключ до temporal coherence
self.model = torch.jit.load(model_path).to(device)
self.model.eval()
self.transform = T.ToTensor()
# Recurrent state зберігається між кадрами
self.rec = [None] * 4
def reset_state(self):
"""Скинути стан при зміні сцени/джерела"""
self.rec = [None] * 4
@torch.no_grad()
def process_frame(self, frame_bgr: np.ndarray,
background_bgr: np.ndarray) -> np.ndarray:
"""
Обробка одного кадру відео.
Стан (rec) зберігається між викликами для плавності.
"""
frame_rgb = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
bg_rgb = cv2.cvtColor(background_bgr, cv2.COLOR_BGR2RGB)
# Змінюємо розмір до кратного 64 для моделі
h, w = frame_rgb.shape[:2]
src = self.transform(Image.fromarray(frame_rgb)).unsqueeze(0).to(self.device)
bgr_tensor = self.transform(
Image.fromarray(bg_rgb).resize((w, h))
).unsqueeze(0).to(self.device)
# Основний вивід з передачею recurrent state
fgr, pha, *self.rec = self.model(src, *self.rec, downsample_ratio=0.25)
# Compositing
composite = fgr * pha + bgr_tensor * (1 - pha)
result = (composite.squeeze().permute(1, 2, 0).cpu().numpy() * 255).astype(np.uint8)
return cv2.cvtColor(result, cv2.COLOR_RGB2BGR)
def replace_in_video(self, input_path: str,
background_path: str,
output_path: str) -> dict:
cap = cv2.VideoCapture(input_path)
fps = cap.get(cv2.CAP_PROP_FPS)
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Завантажуємо фон (може бути зображення або відео)
if background_path.endswith(('.jpg', '.png')):
bg = cv2.imread(background_path)
bg = cv2.resize(bg, (w, h))
bg_is_video = False
else:
bg_cap = cv2.VideoCapture(background_path)
bg_is_video = True
out = cv2.VideoWriter(output_path,
cv2.VideoWriter_fourcc(*'mp4v'),
fps, (w, h))
self.reset_state()
frame_count = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
if bg_is_video:
ret_bg, bg = bg_cap.read()
if not ret_bg:
bg_cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
_, bg = bg_cap.read()
bg = cv2.resize(bg, (w, h))
result = self.process_frame(frame, bg)
out.write(result)
frame_count += 1
cap.release()
out.release()
return {'frames': frame_count, 'fps': fps, 'output': output_path}
Які моделі забезпечують realtime на CPU?
Для CPU без GPU ми використовуємо ONNX Runtime з оптимізаціями. У проєкті для відеоконференцій ми досягли 30 FPS на ноутбуці Intel i5, застосувавши квантизацію INT8 та зменшення роздільної здатності до 256x144. ONNX Runtime дозволяє запускати моделі на різних пристроях з мінімальними змінами.
import onnxruntime as ort
class RealtimeBackgroundProcessor:
"""
ONNX Runtime для CPU-оптимізації на машинах без GPU.
Target: 30 FPS на ноутбуці, затримка <33 мс/кадр.
"""
def __init__(self, onnx_model_path: str):
# Налаштування для максимальної продуктивності на CPU
opts = ort.SessionOptions()
opts.intra_op_num_threads = 4
opts.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL
opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
self.session = ort.InferenceSession(
onnx_model_path,
sess_options=opts,
providers=['TensorrtExecutionProvider',
'CUDAExecutionProvider',
'CPUExecutionProvider']
)
# Recurrent state як numpy масиви
self.rec_states = [
np.zeros((1, 1, 1, 1), dtype=np.float32) for _ in range(4)
]
def process_frame_fast(self, frame_rgb: np.ndarray,
target_size: tuple = (256, 144)) -> np.ndarray:
"""
Зменшуємо до 256x144 для CPU realtime.
Upscale маски назад через білінійну інтерполяцію.
"""
orig_h, orig_w = frame_rgb.shape[:2]
small = cv2.resize(frame_rgb, target_size)
small_f = small.astype(np.float32) / 255.0
src = small_f.transpose(2, 0, 1)[np.newaxis] # [1, 3, H, W]
outputs = self.session.run(
None,
{'src': src, 'r1i': self.rec_states[0], 'r2i': self.rec_states[1],
'r3i': self.rec_states[2], 'r4i': self.rec_states[3],
'downsample_ratio': np.array([0.25])}
)
fgr, pha = outputs[0], outputs[1]
self.rec_states = list(outputs[2:6])
# Апскейл маски назад до вихідного розміру
alpha_small = pha[0, 0]
alpha_full = cv2.resize(alpha_small, (orig_w, orig_h),
interpolation=cv2.INTER_LINEAR)
return alpha_full
Віртуальний розмитий фон (Bokeh effect)
def apply_background_blur(frame: np.ndarray,
alpha: np.ndarray,
blur_radius: int = 25) -> np.ndarray:
"""
Альтернатива заміні — розмиття фону (як у Google Meet/Teams).
Не вимагає завантаження зображення, працює швидше.
"""
# Розмиваємо весь кадр
blurred = cv2.GaussianBlur(frame, (blur_radius * 2 + 1, blur_radius * 2 + 1), 0)
# Compositing з м'якими краями
alpha_3ch = np.stack([alpha, alpha, alpha], axis=2)
result = (frame * alpha_3ch + blurred * (1 - alpha_3ch)).astype(np.uint8)
return result
Порівняння моделей: яка краще?
RVM краще MediaPipe у 2–3 рази за якістю маски, але потребує GPU для realtime. Background Matting V2 дає кращу якість, але повільніше. Вибір залежить від вашого сценарію: для стрімів підійде RVM MobileNetV3, для офлайн-продакшену — ResNet50.
| Метод | FPS (CPU) | FPS (GPU) | Якість |
|---|---|---|---|
| RVM MobileNetV3 | 28–35 | 100–140 | Висока |
| MediaPipe Selfie Segmentation | 60+ | — | Середня |
| RVM ResNet50 | 8–12 | 45–60 | Найкраща |
| Background Matting V2 | 5–8 | 30–40 | Висока |
Типові помилки при інтеграції AI-заміни фону
| Помилка | Наслідок | Рішення |
|---|---|---|
| Ігнорування temporal coherence | Мерехтіння фону, артефакти | Використовувати RVM або інші рекурентні моделі |
| Неоптимальна роздільна здатність | Низький FPS або погана якість маски | Підбирати розмір так, щоб зберегти баланс; для CPU використовувати 256x144 |
| Відсутність квантизації | Уповільнення інференсу на CPU | Застосувати INT8 квантизацію в ONNX |
| Неправильний вибір моделі | Невідповідність вимогам за швидкістю/якістю | Провести бенчмаркінг на цільовому залізі |
Що входить у роботу?
Ми надаємо:
- Аналіз вашого сценарію та вибір моделі
- Інтеграцію у вашу інфраструктуру (API, WebRTC, мобільний застосунок)
- Оптимізацію під цільове залізо (CPU/GPU/Edge)
- Документацію та навчання команди
- Підтримку після впровадження
Зв'яжіться з нами для аудиту вашого проєкту — ми оцінимо вимоги та запропонуємо оптимальне рішення.
Як вибрати модель для заміни фону?
При виборі моделі враховуйте: цільове обладнання (CPU/GPU), необхідну роздільну здатність та FPS, допустиму затримку. Для мобільних пристроїв краще підходить MediaPipe, для продакшену — RVM з ONNX. Ми допоможемо підібрати конфігурацію та оптимізувати під ваш сценарій.
Процес роботи
- Аналітика: вивчаємо вимоги до FPS, затримок, якості маски.
- Проектування: вибираємо модель, стек (ONNX, PyTorch, TensorRT).
- Реалізація: пишемо код інтеграції, додаємо рекурентний стан.
- Тестування: вимірюємо latency p99, FLOPS, перевіряємо на різних сценах.
- Деплой: розгортаємо на ваших серверах або в хмарі.
Терміни та вартість
Орієнтовні терміни:
- Інтеграція RVM для відеофайлів: 1–2 тижні.
- Realtime плагін для відеоконференцій: 4–8 тижнів.
- Мобільний застосунок: 8–14 тижнів.
Вартість розраховується індивідуально після аудиту проєкту. У нас більше 5 років досвіду в AI/ML, ми реалізували понад 30 проєктів з комп'ютерного зору. Гарантуємо якість маски та дотримання термінів. Замовте розробку під ключ — отримайте готове рішення з гарантією.







