Freigeben über


Erste Schritte mit AI Video Super Resolution (VSR)

Video Super Resolution (VSR) ist eine KI-basierte Video-Up-Sampling-Technologie, mit der Videodatenströme mit niedriger Auflösung von Personen intelligent hochskaliert werden, Schärfe und Details wiederhergestellt werden, die andernfalls aufgrund von Bandbreitenbeschränkungen, schlechten Netzwerkbedingungen, Komprimierung oder Inhalten mit niedrigerer Qualität verloren gehen würden.

Das Hinzufügen von VSR-Funktionen zu Ihrer App ermöglicht Szenarien wie die folgenden:

  • Verbessern der Videoqualität über schlechte Netzwerkverbindungen
  • Bandbreitenoptimierung zur Reduzierung der CDN-Kosten
  • Szenarien mit hoher Bandbreite wie Gruppenvideoanrufe mit mehreren Teilnehmern
  • Verbessern der Videoqualität in sozialen Medien beim Bearbeiten, Hochladen oder Anzeigen

Das VSR-Feature erfordert derzeit einen Copilot+ PC mit einer NPU. Weitere Informationen finden Sie unter Entwickeln von KI-Anwendungen für Copilot+ PCs.

Diese VSR-APIs verwenden Machine Learning (ML)-Modelle und wurden speziell für Szenarien wie Videoanruf- und Konferenz-Apps sowie soziale Netzwerke und Kurzvideos entwickelt, die menschliche Gesichter beim Sprechen zeigen.

VSR unterstützt derzeit die folgenden Auflösungs-, Format- und FPS-Bereiche:

Merkmal Unterstützte Inhalte
Eingabeauflösung 240p – 1440p
Ausgabeauflösung 480p – 1440p
Bilder pro Sekunde (FPS)-Bereich 15 fps – 60 fps
Eingabepixelformat BGR (ImageBuffer-API), NV12 (Direct3D-API)
Ausgabepixelformat BGR (ImageBuffer-API), BGRA (Direct3D-API)

Eine VideoScaler-Sitzung erstellen

Das folgende Beispiel zeigt, wie Eine VSR-Sitzung erstellt wird. Rufen Sie zunächst eine Instanz von ExecutionProviderCatalog ab, und rufen Sie "EnsureAndRegisterCertifiedAsync " auf, um die verfügbaren Modelle zu laden. Rufen Sie GetReadyState in der VideoScalar-Klasse auf, um zu ermitteln, ob der Videoskaler bereit für die Verarbeitung von Frames ist. Wenn nicht, rufen Sie EnsureReadyAsync auf, um den Videoskaler zu initialisieren.


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

Skalieren eines Videoframes

Im folgenden Codebeispiel wird die VideoScaler.ScaleFrame-Methode verwendet, um Bilddaten in einem VideoFrame-Objekt zu verkleineren. Mit der MediaFrameReader-Klasse können Sie VideoFrame von einer Kamera abrufen. Weitere Informationen finden Sie unter Verarbeiten von Medienframes mit MediaFrameReader. Sie können auch das WinUI Community Toolkit CameraPreview-Steuerelement verwenden, um VideoFrame-Objekte von der Kamera abzurufen.

Als Nächstes wird eine Direct3DSurface aus dem Eingabevideoframe abgerufen, und eine weitere Direct3DSurface wird für die Ausgabe des Upscaling-Prozesses erstellt. VideoScaler.ScaleFrame wird aufgerufen, um den Frame zu skalieren. In diesem Beispiel wird ein Bildsteuerelement in der Benutzeroberfläche der App mit dem hochskalierten Frame aktualisiert.

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

Skalieren einer SoftwareBitmap mit ImageBuffer

Im folgenden Codebeispiel wird die Verwendung der VideoScalar-Klasse zum Hochskalieren einer SoftwareBitmap veranschaulicht. Dieses Beispiel stellt keine typische Verwendung der VSR-APIs dar. Es ist weniger leistungsfähig als Direct3D. Sie können dieses Beispiel jedoch verwenden, um mit den VSR-APIs zu experimentieren, ohne eine Kamera- oder Videostreamingpipeline einzurichten. Da für die Videoskalierung bei Verwendung eines ImageBuffers ein BGR8 erforderlich ist, sind einige Hilfsmethoden erforderlich, um das Pixelformat der bereitgestellten SoftwareBitmap zu konvertieren.

Der Beispielcode in diesem Artikel basiert auf der VSR-Komponente der Windows AI-API-Beispiele.

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

Software-Bitmaperweiterungsmethoden

Die folgenden Hilfsmethoden konvertieren ein SoftwareBitmap-Format zwischen BGRA8 - und BGR8-Formaten , um den Eingabe- und Ausgabeanforderungen des Videoskakalers zu entsprechen.

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

Verantwortungsvolle KI

Wir haben eine Kombination der folgenden Schritte verwendet, um sicherzustellen, dass diese Imageerstellungs-APIs vertrauenswürdig, sicher und verantwortungsbewusst erstellt sind. Es wird empfohlen, die bewährten Methoden zu überprüfen, die bei der Implementierung von KI-Features in Ihrer App in der verantwortungsvollen generativen KI-Entwicklung unter Windows beschrieben sind.

Diese VSR-APIs verwenden Modelle des Maschinellen Lernens (ML), die speziell für Szenarien wie Videoanruf- und Konferenz-Apps sowie soziale und Kurzform-Videos entwickelt wurden, die menschliche Gesichter zeigen, die sprechen. Daher wird die Verwendung dieser APIs für Bilder in den folgenden Szenarien nicht empfohlen:

  • Wenn Bilder potenziell sensible Inhalte zeigen und durch ungenaue Beschreibungen umstritten sein könnten, wie z. B. Flaggen, Karten, Globen, kulturelle Symbole oder religiöse Symbole.
  • Wenn genaue Beschreibungen wichtig sind, z. B. für medizinische Beratung oder Diagnose, rechtliche Inhalte oder Finanzdokumente.

Siehe auch