Partilhar via


Introdução à Super Resolução de Vídeo AI (VSR)

Video Super Resolution (VSR) é uma tecnologia de upsampling de vídeo baseada em IA que escalona de forma inteligente fluxos de vídeo de baixa resolução de pessoas, restaurando nitidez e detalhes que, de outra forma, seriam perdidos devido a limitações de largura de banda, más condições de rede, compressão ou conteúdo de origem de baixa qualidade.

Adicionar recursos VSR ao seu aplicativo permite cenários que incluem o seguinte:

  • Melhorar a qualidade de vídeo através de ligações de rede deficientes
  • Otimização da largura de banda para reduzir os custos de CDN
  • Cenários de alta largura de banda, como chamadas de vídeo em grupo com vários participantes
  • Melhorar a qualidade do vídeo das redes sociais na edição, upload ou visualização

O recurso VSR atualmente requer um PC Copilot+ com uma NPU. Para obter mais informações, consulte Desenvolver aplicativos de IA para PCs Copilot+.

Essas APIs VSR usam modelos de Machine Learning (ML), foram projetadas especificamente para cenários como aplicativos de videochamada e conferência e vídeos sociais e curtos que apresentam rostos humanos falando

Atualmente, o VSR suporta os seguintes intervalos de resolução, formato e FPS:

Attribute Conteúdo suportado
Resolução de entrada 240p – 1440p
Resolução de saída 480p – 1440p
Intervalo de quadros por segundo (FPS) 15 fps – 60 fps
Formato de píxel de entrada BGR (API ImageBuffer), NV12 (API Direct3D)
Formato de píxel de saída BGR (API ImageBuffer), BGRA (API Direct3D)

Criar uma sessão VideoScaler

O exemplo a seguir mostra como criar uma sessão VSR. Primeiro, obtenha uma instância de ExecutionProviderCatalog e chame EnsureAndRegisterCertifiedAsync para carregar os modelos disponíveis. Chame GetReadyState na classe VideoScalar para determinar se o escalador de vídeo está pronto para processar quadros. Caso contrário, chame EnsureReadyAsync para inicializar o escalador de vídeo.


private VideoScaler? _videoScaler;

protected override async Task LoadModelAsync(SampleNavigationParameters sampleParams)
{
    try
    {

        var catalog = ExecutionProviderCatalog.GetDefault();
        await catalog.EnsureAndRegisterCertifiedAsync();

        var readyState = VideoScaler.GetReadyState();
        if (readyState == AIFeatureReadyState.NotReady)
        {
            var operation = await VideoScaler.EnsureReadyAsync();

            if (operation.Status != AIFeatureReadyResultState.Success)
            {
                ShowException(null, "Video Scaler is not available.");
            }
        }

        _videoScaler = await VideoScaler.CreateAsync();
    }
    catch (Exception ex)
    {
        ShowException(ex, "Failed to load model.");
    }

    sampleParams.NotifyCompletion();
}

Dimensionar um Quadro de Vídeo

O exemplo de código a seguir usa o método VideoScaler.ScaleFrame para ampliar dados de imagem contidos num objeto VideoFrame. Você pode obter VideoFrame de uma câmera usando a classe MediaFrameReader . Para obter mais informações, consulte Processar quadros de mídia com MediaFrameReader. Você também pode usar o controle WinUI Community Toolkit CameraPreview para obter objetos VideoFrame da câmera.

Em seguida, um Direct3DSurface é obtido a partir do quadro de vídeo de entrada e outro Direct3DSurface é criado para a saída do upscaling. VideoScaler.ScaleFrame é chamado para aumentar o frame. Neste exemplo, um controlo Image na interface de utilizador do aplicativo é atualizado com o quadro aumentado.

 private async Task ProcessFrame(VideoFrame videoFrame)
{
    // Process the frame with super resolution model
    var processedBitmap = await Task.Run(async () =>
    {
        int width = 0;
        int height = 0;
        var inputD3dSurface = videoFrame.Direct3DSurface;
        if (inputD3dSurface != null)
        {
            Debug.Assert(inputD3dSurface.Description.Format == Windows.Graphics.DirectX.DirectXPixelFormat.NV12, "input in NV12 format");
            width = inputD3dSurface.Description.Width;
            height = inputD3dSurface.Description.Height;
        }
        else
        {
            var softwareBitmap = videoFrame.SoftwareBitmap;
            if (softwareBitmap == null)
            {
                return null;
            }

            Debug.Assert(softwareBitmap.BitmapPixelFormat == BitmapPixelFormat.Nv12, "input in NV12 format");

            width = softwareBitmap.PixelWidth;
            height = softwareBitmap.PixelHeight;
        }

        try
        {
            if (inputD3dSurface == null)
            {
                // Create Direct3D11-backed VideoFrame for input
                using var inputVideoFrame = VideoFrame.CreateAsDirect3D11SurfaceBacked(
                    Windows.Graphics.DirectX.DirectXPixelFormat.NV12,
                    width,
                    height);

                if (inputVideoFrame.Direct3DSurface == null)
                {
                    return null;
                }

                // Copy the software bitmap to the Direct3D-backed frame
                await videoFrame.CopyToAsync(inputVideoFrame);

                inputD3dSurface = inputVideoFrame.Direct3DSurface;
            }

            // Create or resize output surface (BGRA8 format for display)
            if (_outputD3dSurface == null || _outputWidth != width || _outputHeight != height)
            {
                _outputD3dSurface?.Dispose();

                // DXGI_FORMAT_B8G8R8A8_UNORM = 87
                _outputD3dSurface = Direct3DExtensions.CreateDirect3DSurface(87, width, height);
                _outputWidth = width;
                _outputHeight = height;
            }

            // Scale the frame using VideoScaler
            var result = _videoScaler!.ScaleFrame(inputD3dSurface, _outputD3dSurface, new VideoScalerOptions());

            if (result.Status == ScaleFrameStatus.Success)
            {
                var outputBitmap = await SoftwareBitmap.CreateCopyFromSurfaceAsync(
                    _outputD3dSurface,
                    BitmapAlphaMode.Premultiplied);

                return outputBitmap;
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"ProcessFrame error: {ex.Message}");
        }

        return null;
    });

    if (processedBitmap == null)
    {
        return;
    }

    DispatcherQueue.TryEnqueue(async () =>
    {
        using (processedBitmap)
        {
            var source = new SoftwareBitmapSource();
            await source.SetBitmapAsync(processedBitmap);
            ProcessedVideoImage.Source = source;
        }
    });
}

Dimensionar um SoftwareBitmap usando ImageBuffer

O exemplo de código a seguir demonstra o uso da classe VideoScalar para aumentar a resolução de um SoftwareBitmap. Este exemplo não representa um uso típico das APIs VSR. Tem menos desempenho do que usar o Direct3D. Mas você pode usar este exemplo para experimentar as APIs VSR sem configurar uma câmera ou pipeline de streaming de vídeo. Como o dimensionador de vídeo requer um BGR8 ao usar um ImageBuffer, alguns métodos auxiliares são necessários para converter o formato de pixel do SoftwareBitmap fornecido.

O código de exemplo neste artigo baseia-se no componente VSR das amostras da API de IA do Windows

    public SoftwareBitmap ScaleVideoFrame(SoftwareBitmap inputFrame)
    {
        ImageBuffer inputImageBuffer = SoftwareBitmapExtensions.ConvertToBgr8ImageBuffer(inputFrame);
        var size = (uint)(inputFrame.PixelWidth * inputFrame.PixelHeight * 3);
        IBuffer outputBuffer = new global::Windows.Storage.Streams.Buffer(size);
        outputBuffer.Length = size;
        ImageBuffer outputImageBuffer = ImageBuffer.CreateForBuffer(
            outputBuffer,
            ImageBufferPixelFormat.Bgr8,
            inputFrame.PixelWidth,
            inputFrame.PixelHeight,
            inputFrame.PixelWidth * 3);
        var result = Session.ScaleFrame(inputImageBuffer, outputImageBuffer, new VideoScalerOptions());
        if (result.Status != ScaleFrameStatus.Success)
        {
            throw new Exception($"Failed to scale video frame: {result.Status}");
        }

        return SoftwareBitmapExtensions.ConvertBgr8ImageBufferToBgra8SoftwareBitmap(outputImageBuffer);
    }

Métodos de extensão para bitmaps em software

Os seguintes métodos auxiliares convertem um SoftwareBitmap entre os formatos BGRA8 e BGR8 para corresponder aos requisitos de entrada e saída do escalar de vídeo.

public static ImageBuffer ConvertToBgr8ImageBuffer(SoftwareBitmap input)
    {
        var bgraBitmap = input;
        if (input.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
        {
            bgraBitmap = SoftwareBitmap.Convert(input, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
        }

        int width = bgraBitmap.PixelWidth;
        int height = bgraBitmap.PixelHeight;

        byte[] bgraBuffer = new byte[width * height * 4];
        bgraBitmap.CopyToBuffer(bgraBuffer.AsBuffer());

        byte[] bgrBuffer = new byte[width * height * 3];
        for (int i = 0, j = 0; i < bgraBuffer.Length; i += 4, j += 3)
        {
            bgrBuffer[j] = bgraBuffer[i];
            bgrBuffer[j + 1] = bgraBuffer[i + 1];
            bgrBuffer[j + 2] = bgraBuffer[i + 2];
        }

        return ImageBuffer.CreateForBuffer(
            bgrBuffer.AsBuffer(),
            ImageBufferPixelFormat.Bgr8,
            width,
            height,
            width * 3);
    }

    public static SoftwareBitmap ConvertBgr8ImageBufferToBgra8SoftwareBitmap(ImageBuffer bgrImageBuffer)
    {
        if (bgrImageBuffer.PixelFormat != ImageBufferPixelFormat.Bgr8)
        {
            throw new ArgumentException("Input ImageBuffer must be in Bgr8 format");
        }

        int width = bgrImageBuffer.PixelWidth;
        int height = bgrImageBuffer.PixelHeight;

        // Get BGR data from ImageBuffer
        byte[] bgrBuffer = new byte[width * height * 3];
        bgrImageBuffer.CopyToByteArray(bgrBuffer);

        // Create BGRA buffer (4 bytes per pixel)
        byte[] bgraBuffer = new byte[width * height * 4];

        for (int i = 0, j = 0; i < bgrBuffer.Length; i += 3, j += 4)
        {
            bgraBuffer[j] = bgrBuffer[i];     // B
            bgraBuffer[j + 1] = bgrBuffer[i + 1]; // G
            bgraBuffer[j + 2] = bgrBuffer[i + 2]; // R
            bgraBuffer[j + 3] = 255;              // A (full opacity)
        }

        // Create SoftwareBitmap and copy data
        var softwareBitmap = new SoftwareBitmap(
            BitmapPixelFormat.Bgra8,
            width,
            height,
            BitmapAlphaMode.Premultiplied);

        softwareBitmap.CopyFromBuffer(bgraBuffer.AsBuffer());

        return softwareBitmap;
    }

Inteligência Artificial responsável

Usamos uma combinação das etapas a seguir para garantir que essas APIs de criação de imagens sejam confiáveis, seguras e criadas de forma responsável. Recomendamos rever as práticas recomendadas descritas em Desenvolvimento de IA Generativa Responsável no Windows ao implementar recursos de IA em seu aplicativo.

Essas APIs VSR usam modelos de Machine Learning (ML), foram projetadas especificamente para cenários como aplicativos de videochamada e conferência e vídeos sociais e curtos que apresentam rostos humanos falando. Portanto, não recomendamos o uso dessas APIs para imagens nos seguintes cenários:

  • Quando as imagens contêm conteúdo potencialmente sensível e descrições imprecisas podem ser controversas, como bandeiras, mapas, globos, símbolos culturais ou símbolos religiosos.
  • Quando descrições precisas são críticas, como para aconselhamento médico ou diagnóstico, conteúdo legal ou documentos financeiros.

Consulte também