次の方法で共有


AI ビデオスーパー解像度 (VSR) を始める

Video Super Resolution (VSR) は AI ベースのビデオ アップ サンプリング テクノロジであり、人々の低解像度のビデオ ストリームをインテリジェントにスケールアップし、帯域幅の制限、ネットワーク条件の低下、圧縮、または低品質のソース コンテンツによって失われる可能性のある鮮明さと詳細を復元します。

アプリに VSR 機能を追加すると、次のようなシナリオが可能になります。

  • ネットワーク接続が不十分な場合のビデオ品質の向上
  • CDN コストを削減するための帯域幅の最適化
  • 複数の参加者によるグループ ビデオ通話などの高帯域幅シナリオ
  • 編集、アップロード、または表示におけるソーシャル メディア ビデオの品質の向上

VSR 機能には現在、NPU を搭載 した Copilot+ PC が必要です。 詳細については、「 Copilot+ PC 用の AI アプリケーションの開発」を参照してください。

これらの VSR API は Machine Learning (ML) モデルを使用します。ビデオ通話や会議アプリ、人の顔を話すソーシャルビデオや短い形式のビデオなどのシナリオ専用に設計されています

VSR では現在、次の解像度、形式、FPS 範囲がサポートされています。

特性 サポートされているコンテンツ
入力解像度 240p – 1440p
出力解像度 480p – 1440p
1 秒あたりのフレーム数 (FPS) 範囲 15 fps – 60 fps
入力ピクセル形式 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();
}

VideoFrame のスケーリング

次のコード例では、 VideoScaler.ScaleFrame メソッドを使用して 、VideoFrame オブジェクトに含まれるイメージ データをアップスケールします。 MediaFrameReader クラスを使用して、カメラから VideoFrame を取得できます。 詳細については、「 MediaFrameReader を使用したメディア フレームの処理」を参照してください。 WinUI Community Toolkit 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);
    }

ソフトウェア ビットマップ拡張メソッド

次のヘルパーメソッドは、SoftwareBitmapBGRA8 形式と BGR8 形式の間で、ビデオスカラーの入力要件と出力要件に合わせて変換します。

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

責任ある AI

これらのイメージング API が信頼でき、安全で、責任を持って構築されていることを確認するために、次の手順を組み合わせて使用しました。 アプリで AI 機能を実装する場合は、「Windows での責任ある生成 AI 開発」で説明されているベスト プラクティスを確認することをお勧めします。

これらの VSR API は Machine Learning (ML) モデルを使用し、ビデオ通話や会議アプリなどのシナリオや、人の顔を話すソーシャルビデオや短い形式のビデオに特化して設計されています。 そのため、以下のシナリオにおける画像には、これらの API の使用はお勧めできません。

  • 画像にセンシティブな内容 (国旗、地図、地球儀、文化的シンボル、宗教的シンボルなど) が含まれる場合。不正確な説明により、論争を招く可能性があります。
  • 医療に関するアドバイスや診断、法的コンテンツ、財務文書など、正確な説明が不可欠な場合。

こちらも参照ください