Compartir a través de


Introducción a AI Super Resolución de Video (VSR)

La Súper Resolución de Video (VSR) es una tecnología de escalado de vídeo basada en IA que escala inteligentemente las secuencias de vídeo de baja resolución, restaurando la nitidez y los detalles que, de lo contrario, se perderían debido a limitaciones de ancho de banda, condiciones de red deficientes, compresión o contenido de origen de menor calidad.

La adición de funcionalidades de VSR a la aplicación permite escenarios que incluyen lo siguiente:

  • Mejora de la calidad del vídeo a través de conexiones de red deficientes
  • Optimización del ancho de banda para reducir los costos de la red CDN
  • Escenarios de alto ancho de banda, como las videollamadas grupales con varios participantes
  • Mejora de la calidad del vídeo de redes sociales en la edición, carga o visualización

Actualmente, la característica VSR requiere un PC de Copilot+ con una NPU. Para obtener más información, consulte Desarrollar aplicaciones de inteligencia artificial para PCs con Copilot+.

Estas API de VSR usan modelos de Machine Learning (ML) diseñados específicamente para escenarios como aplicaciones de videollamadas y conferencias y vídeos sociales y de formato corto que incluyen caras humanas hablando

VSR admite actualmente los siguientes intervalos de resolución, formato y FPS:

Atributo Contenido compatible
Resolución de entrada 240p – 1440p
Resolución de salida 480p – 1440p
Intervalo de fotogramas por segundo (FPS) 15 fps – 60 fps
Formato de píxel de entrada BGR (ImageBuffer API), NV12 (API de Direct3D)
Formato de píxel de salida BGR (ImageBuffer API), BGRA (API de Direct3D)

Creación de una sesión de VideoScaler

En el ejemplo siguiente se muestra cómo crear una sesión de VSR. En primer lugar, obtenga una instancia de ExecutionProviderCatalog y llame a EnsureAndRegisterCertifiedAsync para cargar los modelos disponibles. Llame a GetReadyState en la clase VideoScalar para determinar si el escalador de vídeo está listo para procesar fotogramas. Si no es así, llame a EnsureReadyAsync para inicializar el 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();
}

Escalado de un videoframe

En el ejemplo de código siguiente se usa el método VideoScaler.ScaleFrame para escalar verticalmente los datos de imagen contenidos en un objeto VideoFrame . Puede obtener VideoFrame desde una cámara mediante la clase MediaFrameReader . Para obtener más información, vea Procesar fotogramas multimedia con MediaFrameReader. También puede usar el control CameraPreview del kit de herramientas de la comunidad winUI para obtener objetos VideoFrame de la cámara.

A continuación, se obtiene un Direct3DSurface del fotograma de vídeo de entrada y se crea otro Direct3DSurface para la salida del escalado ascendente. Se llama a VideoScaler.ScaleFrame para escalar verticalmente el fotograma. En este ejemplo, un control Image en la interfaz de usuario de la aplicación se actualiza con el marco escalado.

 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;
        }
    });
}

Escalar un SoftwareBitmap usando ImageBuffer

En el ejemplo de código siguiente se muestra el uso de la clase VideoScalar para escalar verticalmente un SoftwareBitmap. Este ejemplo no representa un uso típico de las API de VSR. Es menos eficaz que usar Direct3D. Pero puede usar este ejemplo para experimentar con las API de VSR sin configurar una canalización de streaming de vídeo o cámara. Dado que el escalador de vídeo requiere un BGR8 al usar imageBuffer, se requieren algunos métodos auxiliares para convertir el formato de píxel del softwareBitmap proporcionado.

El código de ejemplo de este artículo se basa en el componente VSR de los ejemplos de la API de IA de 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 extensión para mapas de bits en software

Los siguientes métodos auxiliares convierten un softwareBitmap entre formatos BGRA8 y BGR8 para que coincidan con los requisitos de entrada y salida del 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;
    }

Inteligencia artificial responsable

Hemos usado una combinación de los pasos siguientes para asegurarse de que estas API de creación de imágenes son confiables, seguras y creadas de forma responsable. Se recomienda revisar las mejores prácticas descritas en Desarrollo de IA Generativa Responsable en Windows al implementar características de inteligencia artificial en tu aplicación.

Estas API de VSR usan modelos de Machine Learning (ML), se diseñaron específicamente para escenarios como videollamadas y conferencias y vídeos sociales y de formato corto que presentan caras humanas hablando. Por lo tanto, no se recomienda usar estas API para imágenes en los escenarios siguientes:

  • Donde las imágenes contienen contenido potencialmente confidencial y descripciones inexactas podrían ser controvertidas, como banderas, mapas, globos, símbolos culturales o símbolos religiosos.
  • Cuando las descripciones precisas son críticas, como para asesoramiento médico o diagnóstico, contenido legal o documentos financieros.

Consulte también