共用方式為


瞭解 AI 視訊超解析度技術(簡稱 VSR)

視訊超解析度 (VSR) 是一種基於人工智慧的視訊上採樣技術,可智慧地升級人物的低解析度視訊串流,恢復清晰度和細節,否則這些清晰度和細節會因頻寬限制、網路條件不佳、壓縮或品質較低的來源內容而丟失。

將 VSR 功能新增至您的應用程式可啟用下列應用情境:

  • 在網路連線不佳的情況下改善視訊品質
  • 頻寬優化以降低 CDN 成本
  • 高頻寬案例,例如與多個參與者的群組視訊通話
  • 提高編輯、上傳或觀看的社交媒體視頻質量

VSR 功能目前需要一台帶有 NPU 的 Copilot+ PC 。 如需詳細資訊,請參閱 開發適用於 Copilot+ 電腦的 AI 應用程式

這些 VSR API 使用機器學習 (ML) 模型,專為視訊通話和會議應用程式以及以人臉說話為特色的社交和短影片等場景而設計

VSR 目前支援以下解析度、格式和 FPS 範圍:

Attribute 支援的內容
輸入解析度 240p – 1440p
輸出解析度 480p – 1440p
每秒幀數 (FPS) 範圍 15 幀/秒 – 60 幀/秒
輸入像素格式 BGR (ImageBuffer API)、NV12 (Direct3D API)
輸出像素格式 BGR (ImageBuffer API)、BGRA (Direct3D API)

建立 VideoScaler 會話

下列範例顯示如何建立 VSR 會話。 首先,取得 ExecutionProviderCatalog 的實例,並呼叫 EnsureAndRegisterCertifiedAsync 來載入可用的模型。 在 VideoScalar 類別上呼叫 GetReadyState,以判斷視訊縮放器是否已準備好處理畫面。 如果沒有,請呼叫 EnsureReadyAsync 來初始化視訊縮放器。


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

縮放視頻框架

下列程式碼範例會使用 VideoScaler.ScaleFrame 方法來放大 VideoFrame 物件中包含的影像資料。 您可以使用 MediaFrameReader 類別從相機取得 VideoFrame。 如需詳細資訊,請參閱 使用 MediaFrameReader 處理媒體框架。 您也可以使用 WinUI 社群工具組 CameraPreview 控制項,從相機取得 VideoFrame 物件。

接下來,會從輸入影片框取得 Direct3DSurface ,並建立另一個 Direct3DSurface 以用於影像放大處理的輸出。 呼叫 VideoScaler.ScaleFrame 來放大影格。 在此範例中,應用程式 UI 中的 Image 控制項會使用放大的框架進行更新。

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

使用 ImageBuffer 對 SoftwareBitmap 進行縮放

下列程式碼範例示範如何使用 VideoScalar 類別來升級 SoftwareBitmap。 此範例不代表 VSR API 的一般用法。 其效能低於使用 Direct3D。 但您可以使用此範例來試驗 VSR API,而無需設定攝影機或視訊串流管道。 因為視訊縮放器在使用 ImageBuffer 時需要 BGR8,所以需要一些協助程式方法來轉換所提供 SoftwareBitmap 的圖元格式。

本文範例程式碼基於 Windows AI API 範例中的 VSR 元件

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

軟體點陣圖延伸方法

下列協助程式方法會在 BGRA8BGR8 格式之間轉換 SoftwareBitmap,以符合視訊純量的輸入和輸出需求。

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

負責任的人工智慧

我們已使用下列步驟的組合,以確保這些映像 API 值得信任、安全且負責任地建置。 建議您檢閱在應用程式中實作 AI 功能時,在 Windows 上負責任產生 AI 開發 中所述的最佳做法。

這些 VSR API 使用機器學習 (ML) 模型,專為視訊通話和會議應用程式以及以人臉說話為特色的社交和短影片等場景而設計。 因此,在下列案例中,不建議將這些 API 用於影像:

  • 如果影像包含潛在的敏感性內容和不正確的描述,可能會引起爭議,例如旗標、地圖、地球、文化符號或宗教符號。
  • 當正確描述很重要時,例如醫療建議或診斷、法律內容或財務檔。

另請參閱