Реализация AI-увеличения разрешения видео (Video Upscale)

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1 услугВсе 1566 услуг
Реализация AI-увеличения разрешения видео (Video Upscale)
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Направления AI-разработки
Этапы разработки AI-решения
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1218
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    853
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1047
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    825

AI Super-Resolution для видео — апскейл видеоконтента

Апскейл видео сложнее апскейла изображений: temporal consistency — соседние кадры должны выглядеть согласованно, иначе результат мерцает. Просто применить Real-ESRGAN к каждому кадру — неправильно: шум на однородных поверхностях будет меняться от кадра к кадру.

Real-BasicVSR и BasicVSR++ — основные модели

import torch
import numpy as np
import cv2
from basicsr.archs.basicvsrpp_arch import BasicVSRPlusPlus

def upscale_video_basicvsr(
    frames: list[np.ndarray],   # список кадров (H, W, 3) BGR
    scale: int = 4,
    num_feat: int = 64,
    num_propagation_blocks: int = 7,
    cpu_cache_length: int = 100  # кадры в памяти GPU одновременно
) -> list[np.ndarray]:
    """
    BasicVSR++ использует bidirectional propagation:
    информацию из прошлых И будущих кадров.
    cpu_cache_length: при длинных видео часть кадров выгружаем на CPU.
    """
    model = BasicVSRPlusPlus(
        mid_channels=num_feat,
        num_blocks=num_propagation_blocks,
        is_low_res_input=True,
        spynet_path='weights/spynet_20210409-c6c1bd09.pth'
    )
    state_dict = torch.load(
        f'weights/BasicVSR++_reds4_vimeo90k.pth'
    )['params']
    model.load_state_dict(state_dict, strict=True)
    model.eval().cuda()

    # Нормализация и конвертация BGR→RGB
    tensor_frames = []
    for frame in frames:
        f_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        t = torch.from_numpy(f_rgb).float() / 255.0
        t = t.permute(2, 0, 1).unsqueeze(0)  # (1, C, H, W)
        tensor_frames.append(t)

    # Batch всех кадров → (1, T, C, H, W)
    video_tensor = torch.stack(
        [f.squeeze(0) for f in tensor_frames], dim=0
    ).unsqueeze(0).cuda()

    with torch.no_grad(), torch.cuda.amp.autocast():
        output = model(video_tensor)  # (1, T, C, 4H, 4W)

    result = []
    for i in range(output.shape[1]):
        frame_t = output[0, i].float().cpu()
        frame_np = (frame_t.permute(1,2,0).numpy() * 255).clip(0,255)
        result.append(
            cv2.cvtColor(frame_np.astype(np.uint8), cv2.COLOR_RGB2BGR)
        )
    return result

Чанкованная обработка длинных видео

Целый фильм не влезет в VRAM при BasicVSR++. Обработка чанками с overlap:

def upscale_long_video(
    input_path: str,
    output_path: str,
    chunk_frames: int = 50,     # кадров в чанке
    overlap_frames: int = 5,    # перекрытие для бесшовного сшивания
    scale: int = 4
) -> None:
    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))

    writer = cv2.VideoWriter(
        output_path,
        cv2.VideoWriter_fourcc(*'mp4v'),
        fps, (w * scale, h * scale)
    )

    all_frames = []
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        all_frames.append(frame)
    cap.release()

    n = len(all_frames)
    written_up_to = 0

    for start in range(0, n, chunk_frames - overlap_frames):
        end = min(start + chunk_frames, n)
        chunk = all_frames[start:end]

        upscaled_chunk = upscale_video_basicvsr(chunk, scale=scale)

        # Пишем только не-overlap часть (кроме первого чанка)
        write_start = overlap_frames if start > 0 else 0
        for frame in upscaled_chunk[write_start:]:
            writer.write(frame)

        if end == n:
            break

    writer.release()

Сравнение моделей

Модель PSNR Vid4 4x Temporal consistency Скорость 1080p→4K VRAM
Real-ESRGAN (per-frame) 27.4 Низкая (мерцание) ~8fps RTX3080 6GB
BasicVSR 31.4 Хорошая ~2fps RTX3080 12GB
BasicVSR++ 32.4 Отличная ~1.5fps RTX3080 16GB
RVRT 32.8 Отличная ~0.8fps RTX3080 20GB
Real-BasicVSR 31.0 Хорошая ~3fps RTX3080 10GB

Практические кейсы и ограничения

Кейс из практики: оцифровка архивного видео 720p → 4K для OTT-платформы. 180 минут видео, BasicVSR++ с chunk_frames=30. Время обработки на двух RTX A6000: 14 часов. VMAF score вырос с 72 до 89 — платформа приняла качество без ручного ретуширования.

Ограничения: компрессионные артефакты MPEG/H.264 усиливаются SR-моделью. Блочность при высоком QP (>28) → artефакты на 4K выходе. Предобработка через FF_MPEG deblock filter обязательна.

Сроки

Задача Срок
Сервис апскейла видео (Real-BasicVSR) 2–3 недели
Pipeline с препроцессингом + BasicVSR++ 4–6 недель
Fine-tuning под специфический тип контента 8–14 недель