Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini memperlihatkan cara menggunakan pustaka OpenCV (Open Source Computer Vision) dengan MediaFrameReader untuk memproses bingkai kamera secara real time. Teknik ini berguna untuk tugas analisis gambar seperti deteksi tepi, pelacakan objek, dan pengurangan latar belakang dalam aplikasi desktop WinUI 3.
Prasyarat
Sebelum mulai, pastikan bahwa Anda memiliki:
- Proyek desktop WinUI 3 (dikemas atau tidak dikemas).
- Webcam yang kompatibel tersambung ke perangkat Anda.
- Paket OpenCvSharp4 dan OpenCvSharp4.runtime.win NuGet diinstal dalam proyek Anda.
- Akses kamera dideklarasikan untuk aplikasi Anda, seperti yang dijelaskan dalam Mendeklarasikan akses kamera.
Untuk menginstal OpenCV untuk .NET:
dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.runtime.win
Mendeklarasikan akses kamera
Sebelum aplikasi dapat menggunakan MediaFrameReader untuk membaca bingkai dari webcam, Anda harus menyatakan bahwa aplikasi Anda menggunakan kamera. Cara Anda melakukan ini tergantung pada apakah aplikasi Anda dipaketkan.
Aplikasi paket
webcam: Tambahkan kemampuan perangkat kePackage.appxmanifest:<Capabilities> <DeviceCapability Name="webcam" /> </Capabilities>Aplikasi yang tidak dikemas: Aplikasi yang tidak dikemas tidak memiliki manifes paket, sehingga tidak ada kemampuan untuk mendeklarasikan. Akses kamera untuk aplikasi yang tidak dikemas sebaliknya dikontrol oleh pengaturan Izinkan aplikasi desktop mengakses kamera Anda di bawah Pengaturan>Privasi & Kamera keamanan> pada perangkat pengguna.
Dalam kedua kasus, pengguna masih dapat menolak akses kamera di tingkat OS. Periksa akses sebelum Anda menginisialisasi kamera dan menangani kasus yang ditolak dengan baik, seperti yang dijelaskan dalam Menangani pengaturan privasi kamera Windows.
Menyiapkan MediaFrameReader
Pertama, buat MediaCapture instans dan temukan sumber bingkai video warna. Lalu buat MediaFrameReader untuk menerima frame:
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
Atur MemoryPreference ke Cpu sehingga bingkai tiba sebagai SoftwareBitmap objek yang dapat Anda akses langsung dari kode terkelola.
Bingkai proses dengan OpenCV
Di penangan peristiwa FrameArrived, ambil SoftwareBitmap dari frame dan ubah menjadi OpenCV Mat untuk diproses. Anda memerlukan antarmuka IMemoryBufferByteAccess COM untuk mengakses data piksel mentah. Tambahkan definisi ini ke proyek Anda:
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);
}
Kemudian proses bingkai:
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
Blok kode yang tidak aman menggunakan IMemoryBufferByteAccess untuk mendapatkan penunjuk langsung ke data bitmap. Anda perlu mengaktifkan kode tidak aman di pengaturan proyek Anda dengan menambahkan <AllowUnsafeBlocks>true</AllowUnsafeBlocks> ke file Anda .csproj .
Menerapkan operasi OpenCV
Anda dapat menerapkan operasi pemrosesan gambar OpenCV apa pun ke Mat. Berikut adalah contoh yang menerapkan deteksi tepi Canny:
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;
});
}
Image Tambahkan kontrol ke XAML Anda untuk menampilkan bingkai yang diproses:
<Image x:Name="ProcessedImage" Stretch="Uniform" />
Membersihkan sumber daya
Hentikan pembaca bingkai dan lepaskan sumber daya setelah selesai:
private async Task CleanupAsync()
{
if (_frameReader != null)
{
_frameReader.FrameArrived -= FrameReader_FrameArrived;
await _frameReader.StopAsync();
_frameReader.Dispose();
}
_mediaCapture?.Dispose();
_processedBitmap?.Dispose();
}
Konten terkait
Windows developer