Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird gezeigt, wie Sie die OpenCV-Bibliothek (Open Source Maschinelles Sehen) mit einem MediaFrameReader verwenden, um Kameraframes in Echtzeit zu verarbeiten. Diese Technik ist nützlich für Bildanalyseaufgaben wie Edgeerkennung, Objektverfolgung und Hintergrunduntertraktion in einer WinUI 3-Desktop-App.
Prerequisites
Bevor Sie beginnen, stellen Sie sicher, dass Sie folgendes haben:
- Ein WinUI 3-Desktopprojekt (verpackt oder entpackt).
- Eine kompatible Webcam, die mit Ihrem Gerät verbunden ist.
- Die in Ihrem Projekt installierten OpenCvSharp4 - und OpenCvSharp4.runtime.win NuGet-Pakete.
- Für Ihre App deklarierter Kamerazugriff, wie unter "Kamerazugriff deklarieren" beschrieben.
So installieren Sie OpenCV für .NET:
dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.runtime.win
Deklarieren des Kamerazugriffs
Bevor Ihre App zum Lesen von Frames aus einer Webcam verwenden MediaFrameReader kann, müssen Sie deklarieren, dass Ihre App die Kamera verwendet. Wie Sie dies tun, hängt davon ab, ob Ihre App verpackt ist.
Verpackte Apps: Hinzufügen der
webcamGerätefunktion zuPackage.appxmanifest:<Capabilities> <DeviceCapability Name="webcam" /> </Capabilities>Entpackte Apps: Entpackte Apps verfügen nicht über ein Paketmanifest, daher gibt es keine Möglichkeit zum Deklarieren. Der Kamerazugriff für nicht paketierte Apps wird stattdessen durch die Einstellung Desktop-Apps den Zugriff auf Ihre Kamera erlauben unter Einstellungen>Datenschutz & Sicherheit>Kamera auf dem Gerät des Nutzers gesteuert.
In beiden Fällen kann der Benutzer weiterhin den Kamerazugriff auf Betriebssystemebene verweigern. Überprüfen Sie den Zugriff, bevor Sie die Kamera initialisieren und den verweigerten Fall ordnungsgemäß behandeln, wie in der Datenschutzeinstellung für die Windows Kamera beschrieben.
Einrichten des MediaFrameReader
Erstellen Sie zunächst eine MediaCapture Instanz, und suchen Sie eine Farbvideoframequelle. Erstellen Sie dann ein MediaFrameReader, um Frames zu empfangen:
using System.Linq;
using Windows.Media.Capture;
using Windows.Media.Capture.Frames;
using Windows.Graphics.Imaging;
private MediaCapture _mediaCapture;
private MediaFrameReader _frameReader;
private async Task InitializeFrameReaderAsync()
{
// Find a color video source group
var sourceGroups =
await MediaFrameSourceGroup.FindAllAsync();
var selectedGroup = sourceGroups.FirstOrDefault(group =>
group.SourceInfos.Any(info =>
info.MediaStreamType == MediaStreamType.VideoPreview &&
info.SourceKind == MediaFrameSourceKind.Color));
if (selectedGroup == null)
{
// No suitable camera found
return;
}
_mediaCapture = new MediaCapture();
var settings = new MediaCaptureInitializationSettings
{
SourceGroup = selectedGroup,
MemoryPreference = MediaCaptureMemoryPreference.Cpu,
StreamingCaptureMode = StreamingCaptureMode.Video,
};
await _mediaCapture.InitializeAsync(settings);
// Find the color video source
var colorSource = _mediaCapture.FrameSources
.Values.FirstOrDefault(source =>
source.Info.SourceKind == MediaFrameSourceKind.Color);
if (colorSource == null)
{
return;
}
_frameReader =
await _mediaCapture.CreateFrameReaderAsync(colorSource);
_frameReader.FrameArrived += FrameReader_FrameArrived;
await _frameReader.StartAsync();
}
Important
Legen Sie MemoryPreference auf Cpu fest, damit Frames als SoftwareBitmap-Objekte ankommen, auf die Sie direkt aus verwaltetem Code zugreifen können.
Verarbeiten von Frames mit OpenCV
Rufen Sie im Ereignishandler FrameArrived das SoftwareBitmap aus dem Frame ab und konvertieren Sie es zur Verarbeitung in ein OpenCV-Mat. Sie benötigen die IMemoryBufferByteAccess-COM-Schnittstelle , um auf die Rohpixeldaten zuzugreifen. Fügen Sie ihrem Projekt diese Definition hinzu:
using System.Runtime.InteropServices;
[ComImport]
[System.Runtime.InteropServices.Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
void GetBuffer(out byte* buffer, out uint capacity);
}
Verarbeiten Sie dann die Frames:
using OpenCvSharp;
private void FrameReader_FrameArrived(
MediaFrameReader sender,
MediaFrameArrivedEventArgs args)
{
using var frameRef =
sender.TryAcquireLatestFrame();
if (frameRef == null) return;
var bitmap = frameRef.VideoMediaFrame?.SoftwareBitmap;
if (bitmap == null) return;
// Convert to Bgra8 format if needed
SoftwareBitmap convertedBitmap = null;
if (bitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
{
convertedBitmap = SoftwareBitmap.Convert(
bitmap, BitmapPixelFormat.Bgra8);
bitmap = convertedBitmap;
}
// Access the pixel buffer
using var buffer = bitmap.LockBuffer(
BitmapBufferAccessMode.Read);
using var reference =
buffer.CreateReference();
// Get the buffer as a byte array via
// IMemoryBufferByteAccess
unsafe
{
((IMemoryBufferByteAccess)reference).GetBuffer(
out byte* dataInBytes,
out uint capacity);
// Use stride from the buffer plane description
// to avoid corrupted images from padding
var desc = buffer.GetPlaneDescription(0);
using var mat = Mat.FromPixelData(
desc.Height, desc.Width,
MatType.CV_8UC4,
(IntPtr)dataInBytes,
desc.Stride);
// Process the frame with OpenCV
ProcessFrame(mat);
}
// Dispose the converted bitmap if we created one
convertedBitmap?.Dispose();
}
Note
Der unsichere Codeblock verwendet IMemoryBufferByteAccess , um einen direkten Zeiger auf die Bitmapdaten abzurufen. Sie müssen unsicheren Code in Ihren Projekteinstellungen aktivieren, indem Sie <AllowUnsafeBlocks>true</AllowUnsafeBlocks> zu Ihrer .csproj-Datei hinzufügen.
Anwenden von OpenCV-Vorgängen
Sie können jede OpenCV-Bildverarbeitungsoperation auf Mat anwenden. Hier ist ein Beispiel, das die Canny-Edgeerkennung anwendet:
private SoftwareBitmap _processedBitmap;
private void ProcessFrame(Mat inputMat)
{
// Convert to grayscale for edge detection
using var grayMat = new Mat();
Cv2.CvtColor(inputMat, grayMat, ColorConversionCodes.BGRA2GRAY);
// Apply Canny edge detection
using var edges = new Mat();
Cv2.Canny(grayMat, edges, 50, 200);
// Convert back to BGRA for display
using var outputMat = new Mat();
Cv2.CvtColor(edges, outputMat, ColorConversionCodes.GRAY2BGRA);
// Create a SoftwareBitmap from the processed Mat
var processedBitmap = new SoftwareBitmap(
BitmapPixelFormat.Bgra8,
outputMat.Width,
outputMat.Height,
BitmapAlphaMode.Premultiplied);
using var destBuffer = processedBitmap.LockBuffer(
BitmapBufferAccessMode.Write);
using var destRef = destBuffer.CreateReference();
unsafe
{
((IMemoryBufferByteAccess)destRef).GetBuffer(
out byte* destBytes, out uint destCapacity);
// Copy the processed data to the SoftwareBitmap row by row.
// outputMat.Step() and desc.Stride can differ (for example,
// because of OpenCV's own row alignment), so a single bulk
// copy across the whole buffer can corrupt the image. Copying
// one row at a time, using each buffer's own stride, avoids
// that mismatch.
var desc = destBuffer.GetPlaneDescription(0);
int rowBytes = outputMat.Width * outputMat.ElemSize();
byte* sourceRow = (byte*)outputMat.Data.ToPointer();
byte* destRow = destBytes;
for (int row = 0; row < outputMat.Height; row++)
{
System.Buffer.MemoryCopy(
sourceRow,
destRow,
destCapacity - (uint)(row * desc.Stride),
(uint)rowBytes);
sourceRow += outputMat.Step();
destRow += desc.Stride;
}
}
// Update the UI with the processed frame
DispatcherQueue.TryEnqueue(async () =>
{
var source =
new Microsoft.UI.Xaml.Media.Imaging
.SoftwareBitmapSource();
await source.SetBitmapAsync(processedBitmap);
ProcessedImage.Source = source;
_processedBitmap?.Dispose();
_processedBitmap = processedBitmap;
});
}
Fügen Sie Ihrem XAML-Code ein Image Steuerelement hinzu, um die verarbeiteten Frames anzuzeigen:
<Image x:Name="ProcessedImage" Stretch="Uniform" />
Bereinigen von Ressourcen
Beenden Sie den Framereader, und geben Sie Ressourcen frei, wenn Sie fertig sind:
private async Task CleanupAsync()
{
if (_frameReader != null)
{
_frameReader.FrameArrived -= FrameReader_FrameArrived;
await _frameReader.StopAsync();
_frameReader.Dispose();
}
_mediaCapture?.Dispose();
_processedBitmap?.Dispose();
}
Verwandte Inhalte
Windows developer