この記事では、SoftwareBitmap オブジェクトを OpenCV Mat 型に変換するネイティブ C++/WinRT Windows ランタイム コンポーネントを作成する方法について説明します。 これにより、Windows カメラ API でキャプチャされたフレームで OpenCV の広範な画像処理アルゴリズムを使用し、結果を WinUI 3 アプリに表示できます。
Overview
SoftwareBitmap クラスは、Windows メディア API で使用される一般的なイメージ形式ですが、OpenCV では Mat クラスが使用されます。 これらの形式をブリッジするには、次のような C++/WinRT ランタイム コンポーネントを作成します。
-
SoftwareBitmap入力を受け入れます。 - これを OpenCV
Matに変換します。 - 目的の画像処理を適用します。
- 結果を
SoftwareBitmapとして返します。
OpenCV はネイティブ C++ ライブラリであるため、C++/WinRT Windows ランタイム コンポーネント プロジェクトを使用してブリッジを作成します。 C# WinUI 3 アプリがこのコンポーネントを参照しています。
C++/WinRT コンポーネント プロジェクトを設定する
Visual Studioで、新しい Windows ランタイム コンポーネント (C++/WinRT) プロジェクトをソリューションに追加します。
OpenCVBridgeのような名前を付けます。ブリッジ プロジェクトを対象とする パッケージ マネージャー コンソールで次のコマンドを実行して、OpenCV NuGet パッケージをダウンロードします。
Install-Package OpenCV.Windows -ProjectName OpenCVBridgeまたは、 opencv.org から OpenCV リリースをダウンロードし、プロジェクトのインクルード パスとライブラリ パスを手動で構成します。
ブリッジ プロジェクトの
pch.hで、OpenCV ヘッダーを追加します。#include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <robuffer.h> #include <windows.foundation.h>
OpenCVHelper ランタイム クラスを作成する
SoftwareBitmapと OpenCV Matの間で変換するメソッドを提供するランタイム クラスを定義します。 IDL ファイル OpenCVHelper.idl を作成します。
// OpenCVHelper.idl
namespace OpenCVBridge
{
runtimeclass OpenCVHelper
{
OpenCVHelper();
void ProcessBitmap(
Windows.Graphics.Imaging.SoftwareBitmap input,
Windows.Graphics.Imaging.SoftwareBitmap output);
}
}
変換を実装する
OpenCVHelper.cppで、SoftwareBitmapからMatへの変換を実装します。
#include "pch.h"
#include "OpenCVHelper.h"
#include "OpenCVHelper.g.cpp"
#include <opencv2/imgproc.hpp>
using namespace winrt;
using namespace Windows::Graphics::Imaging;
namespace winrt::OpenCVBridge::implementation
{
void OpenCVHelper::ProcessBitmap(
SoftwareBitmap const& input,
SoftwareBitmap const& output)
{
// Lock the input buffer for reading
auto inputBuffer = input.LockBuffer(
BitmapBufferAccessMode::Read);
auto inputRef = inputBuffer.CreateReference();
uint8_t* inputData = nullptr;
uint32_t inputSize = 0;
winrt::check_hresult(
inputRef.as<::Windows::Foundation::
IMemoryBufferByteAccess>()->GetBuffer(
&inputData, &inputSize));
auto inputDesc =
inputBuffer.GetPlaneDescription(0);
// Create a Mat from the input data (use Stride for correct row size)
cv::Mat inputMat(
inputDesc.Height,
inputDesc.Width,
CV_8UC4,
inputData,
inputDesc.Stride);
// Lock the output buffer for writing
auto outputBuffer = output.LockBuffer(
BitmapBufferAccessMode::Write);
auto outputRef = outputBuffer.CreateReference();
uint8_t* outputData = nullptr;
uint32_t outputSize = 0;
winrt::check_hresult(
outputRef.as<::Windows::Foundation::
IMemoryBufferByteAccess>()->GetBuffer(
&outputData, &outputSize));
auto outputDesc =
outputBuffer.GetPlaneDescription(0);
cv::Mat outputMat(
outputDesc.Height,
outputDesc.Width,
CV_8UC4,
outputData,
outputDesc.Stride);
// Apply image processing - example: blur
cv::GaussianBlur(inputMat, outputMat, cv::Size(15, 15), 5);
}
}
Note
上記のコードでは、 IMemoryBufferByteAccess を使用して生のピクセル データにアクセスします。 入力および出力 SoftwareBitmap オブジェクトは、 Bgra8 ピクセル形式を使用する必要があります。 フレーム MediaFrameReader 別の形式を使用する場合は、最初に SoftwareBitmap.Convertで変換します。
C のコンポーネントを使用する#
C# WinUI 3 アプリで、 OpenCVBridge コンポーネントへのプロジェクト参照を追加します。 次に、フレーム処理コードから ProcessBitmap を呼び出します。
using OpenCVBridge;
using Windows.Graphics.Imaging;
private readonly OpenCVHelper _openCVHelper = new();
private void ProcessFrameWithOpenCV(
SoftwareBitmap inputBitmap)
{
// Ensure the bitmap is in Bgra8 format
if (inputBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
{
inputBitmap = SoftwareBitmap.Convert(
inputBitmap, BitmapPixelFormat.Bgra8);
}
// Create an output bitmap with the same dimensions
var outputBitmap = new SoftwareBitmap(
BitmapPixelFormat.Bgra8,
inputBitmap.PixelWidth,
inputBitmap.PixelHeight,
BitmapAlphaMode.Premultiplied);
// Process with OpenCV
_openCVHelper.ProcessBitmap(inputBitmap, outputBitmap);
// Display the result
DispatcherQueue.TryEnqueue(async () =>
{
var source =
new Microsoft.UI.Xaml.Media.Imaging
.SoftwareBitmapSource();
await source.SetBitmapAsync(outputBitmap);
OutputImage.Source = source;
});
}
処理操作をさらに追加する
特定の操作用の追加のメソッドを使用して、 OpenCVHelper クラスを拡張できます。 IDL と実装を更新します。
// Add to OpenCVHelper.idl
void ApplyCannyEdges(
Windows.Graphics.Imaging.SoftwareBitmap input,
Windows.Graphics.Imaging.SoftwareBitmap output,
Double threshold1,
Double threshold2);
// Implementation
void OpenCVHelper::ApplyCannyEdges(
SoftwareBitmap const& input,
SoftwareBitmap const& output,
double threshold1,
double threshold2)
{
// ... lock buffers as above ...
cv::Mat grayMat;
cv::cvtColor(inputMat, grayMat, cv::COLOR_BGRA2GRAY);
cv::Mat edges;
cv::Canny(grayMat, edges, threshold1, threshold2);
cv::cvtColor(edges, outputMat, cv::COLOR_GRAY2BGRA);
}
関連するコンテンツ
Windows developer