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.
Dieser Artikel erklärt, wie man die SoftwareBitmap Klasse verwendet, die von vielen Windows Runtime-APIs genutzt wird, um Bilder darzustellen, in Verbindung mit der Open Source Computer Vision Library (OpenCV), einer quelloffenen, nativen Programmbibliothek, die eine Vielzahl von Bildverarbeitungsalgorithmen bereitstellt.
Die Beispiele in diesem Artikel führen Sie durch das Erstellen einer systemeigenen Windows-Runtime-Komponente, die von einer UWP-App verwendet werden kann, einschließlich Apps, die mit C# erstellt werden. Diese Hilfskomponente stellt eine einzelne Methode bereit, Blur, die die Blur-Bildverarbeitungsfunktion von OpenCV verwendet. Die Komponente implementiert private Methoden, die einen Zeiger auf den zugrunde liegenden Bilddatenpuffer abrufen, der direkt von der OpenCV-Bibliothek verwendet werden kann, wodurch die Hilfskomponente einfach erweitert werden kann, um andere OpenCV-Verarbeitungsfeatures zu implementieren.
- Um eine Einführung in die Verwendung von SoftwareBitmapzu erhalten, sehen Sie sich Erstellen, Bearbeiten und Speichern von Bitmap-Bildernan.
- Informationen zur Verwendung der OpenCV-Bibliothek finden Sie unter https://opencv.org.
- Um die in diesem Artikel vorgestellte OpenCV-Hilfskomponente zusammen mit MediaFrameReader zur Implementierung der Echtzeit-Bildverarbeitung von Kameraframes zu verwenden, siehe Verwenden von OpenCV mit MediaFrameReader.
- Ein vollständiges Codebeispiel, das einige verschiedene Effekte implementiert, finden Sie im Kamera-Frames + OpenCV-Beispiel im Windows Universal Samples GitHub-Repository.
Hinweis
Die in diesem Artikel ausführlich beschriebene Technik der OpenCVHelper-Komponente erfordert, dass sich die zu verarbeitenden Bilddaten im CPU-Speicher und nicht im GPU-Speicher befinden. Für APIs, mit denen Sie den Speicherspeicherort von Bildern anfordern können, z. B. die MediaCapture Klasse, sollten Sie also CPU-Speicher angeben.
Erstellen einer Windows Runtime-Hilfskomponente für die OpenCV-Interoperabilität
1. Fügen Sie Ihrer Lösung ein neues Windows-Runtime-Komponentenprojekt mit systemeigenem Code hinzu.
- Fügen Sie Ihrer Projektmappe in Visual Studio ein neues Projekt hinzu, indem Sie im Projektmappen-Explorer mit der rechten Maustaste auf Projektmappe klicken und Hinzufügen ->Neues Projektauswählen.
- Wählen Sie unter der Kategorie Visual C++ die Windows-Runtime-Komponente (Universelle Windows-Komponente)aus. Nennen Sie in diesem Beispiel das Projekt "OpenCVBridge", und klicken Sie auf OK.
- Wählen Sie im Dialogfeld Neues universelles Windows-Projekt das Ziel und die Mindestversion des Betriebssystems für Ihre App aus, und klicken Sie auf OK.
- Klicken Sie mit der rechten Maustaste auf die automatisch generierte Datei Class1.cpp im Projektmappen-Explorer, und wählen Sie "Entfernen" aus, wenn das Bestätigungsdialogfeld angezeigt wird, " Löschen". Löschen Sie dann die Headerdatei "Class1.h".
- Klicken Sie mit der rechten Maustaste auf das OpenCVBridge-Projektsymbol und wählen Sie Hinzufügen->Klasse aus.... Geben Sie im Dialogfeld Klasse hinzufügen "OpenCVHelper" in das Feld Klassenname ein und klicken Sie dann auf OK. Code wird den erstellten Klassendateien in einem späteren Schritt hinzugefügt.
2. Hinzufügen der OpenCV NuGet-Pakete zu Ihrem Komponentenprojekt
- Klicken Sie im Solution Explorer mit der rechten Maustaste auf das Projektsymbol „OpenCVBridge“ und wählen Sie „NuGet-Pakete verwalten...“ aus
- Wenn das Dialogfeld "NuGet-Paket-Manager" geöffnet wird, wählen Sie die Registerkarte "Durchsuchen" aus, und geben Sie "OpenCV.Win" in das Suchfeld ein.
- Wählen Sie "OpenCV.Win.Core" aus, und klicken Sie auf Installieren. Klicken Sie im Dialogfeld Vorschau auf OK.
- Verwenden Sie dasselbe Verfahren, um das Paket "OpenCV.Win.ImgProc" zu installieren.
Hinweis
OpenCV.Win.Core und OpenCV.Win.ImgProc werden nicht regelmäßig aktualisiert und bestehen nicht die Store-Complianceprüfungen, daher sind diese Pakete nur für Experimente vorgesehen.
3. Implementieren der OpenCVHelper-Klasse
Fügen Sie den folgenden Code in die OpenCVHelper.h-Headerdatei ein. Dieser Code enthält OpenCV-Headerdateien für die Core und ImgProc- Pakete, die wir installiert haben, und deklariert drei Methoden, die in den folgenden Schritten angezeigt werden.
#pragma once
// OpenCVHelper.h
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
namespace OpenCVBridge
{
public ref class OpenCVHelper sealed
{
public:
OpenCVHelper() {}
void Blur(
Windows::Graphics::Imaging::SoftwareBitmap^ input,
Windows::Graphics::Imaging::SoftwareBitmap^ output);
private:
// helper functions for getting a cv::Mat from SoftwareBitmap
bool TryConvert(Windows::Graphics::Imaging::SoftwareBitmap^ from, cv::Mat& convertedMat);
bool GetPointerToPixelData(Windows::Graphics::Imaging::SoftwareBitmap^ bitmap,
unsigned char** pPixelData, unsigned int* capacity);
};
}
Löschen Sie den vorhandenen Inhalt der Datei OpenCVHelper.cpp, und fügen Sie dann die folgenden Include-Direktiven hinzu.
#include "pch.h"
#include "OpenCVHelper.h"
#include "MemoryBuffer.h"
Fügen Sie nach den Include-Direktiven die folgenden -Direktiven mithilfe von hinzu.
using namespace OpenCVBridge;
using namespace Platform;
using namespace Windows::Graphics::Imaging;
using namespace Windows::Foundation;
using namespace Microsoft::WRL;
using namespace cv;
Fügen Sie als Nächstes die Methode GetPointerToPixelData- zum OpenCVHelper.cpp hinzu. Diese Methode verwendet eine SoftwareBitmap- und erhält durch eine Reihe von Konvertierungen eine COM-Schnittstellendarstellung der Pixeldaten, durch die wir einen Zeiger auf den darunterliegenden Datenpuffer als char- Array erhalten können.
Zuerst wird ein BitmapBuffer mit den Pixeldaten abgerufen, indem LockBufferaufgerufen und ein Lese-/Schreibpuffer angefordert wird, damit die OpenCV-Bibliothek diese Pixeldaten ändern kann. CreateReference- wird aufgerufen, um ein IMemoryBufferReference-Objekt abzurufen. Als Nächstes wird die IMemoryBufferByteAccess-Schnittstelle als IInspectable, die Basisschnittstelle aller Windows-Runtime-Klassen, umgewandelt. Danach wird QueryInterface aufgerufen, um eine IMemoryBufferByteAccess- COM-Schnittstelle abzurufen, die es uns ermöglicht, den Pixeldatenpuffer als ein Array vom Typ Char zu erhalten. Füllen Sie schließlich das Char Array auf, indem Sie IMemoryBufferByteAccess::GetBufferaufrufen. Wenn eine der Konvertierungsschritte in dieser Methode fehlschlägt, gibt die Methode falsezurück, was angibt, dass die weitere Verarbeitung nicht fortgesetzt werden kann.
bool OpenCVHelper::GetPointerToPixelData(SoftwareBitmap^ bitmap, unsigned char** pPixelData, unsigned int* capacity)
{
BitmapBuffer^ bmpBuffer = bitmap->LockBuffer(BitmapBufferAccessMode::ReadWrite);
IMemoryBufferReference^ reference = bmpBuffer->CreateReference();
ComPtr<IMemoryBufferByteAccess> pBufferByteAccess;
if ((reinterpret_cast<IInspectable*>(reference)->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess))) != S_OK)
{
return false;
}
if (pBufferByteAccess->GetBuffer(pPixelData, capacity) != S_OK)
{
return false;
}
return true;
}
Fügen Sie als Nächstes die unten gezeigte Methode TryConvert hinzu. Diese Methode nimmt ein SoftwareBitmap und versucht, es in ein Mat Objekt zu konvertieren, welches das Matrixobjekt von OpenCV ist, das zur Darstellung von Bilddatenpuffern verwendet wird. Diese Methode ruft die oben definierte GetPointerToPixelData- Methode auf, um eine Zeichen Arraydarstellung des Pixeldatenpuffers abzurufen. Wenn dies erfolgreich ist, wird der Konstruktor für die Mat-Klasse aufgerufen, wobei die Pixelbreite und -höhe übergeben werden, die aus dem Quellobjekt SoftwareBitmap abgerufen werden.
Hinweis
In diesem Beispiel wird die CV_8UC4 Konstante als Pixelformat für das erstellte Mat-Objekt angegeben. Dies bedeutet, dass die SoftwareBitmap-, die an diese Methode übergeben wird, einen BitmapPixelFormat- Eigenschaftswert BGRA8- mit prämultipliziertem Alpha haben muss, das Äquivalent von CV_8UC4, damit es in diesem Beispiel funktioniert.
Eine flache Kopie des erstellten Mat-Objekts wird von der Methode zurückgegeben, sodass die Weiterverarbeitung mit demselben Datenpixelpuffer ausgeführt wird, auf den die SoftwareBitmap und nicht eine Kopie dieses Puffers verweist.
bool OpenCVHelper::TryConvert(SoftwareBitmap^ from, Mat& convertedMat)
{
unsigned char* pPixels = nullptr;
unsigned int capacity = 0;
if (!GetPointerToPixelData(from, &pPixels, &capacity))
{
return false;
}
Mat mat(from->PixelHeight,
from->PixelWidth,
CV_8UC4, // assume input SoftwareBitmap is BGRA8
(void*)pPixels);
// shallow copy because we want convertedMat.data = pPixels
// don't use .copyTo or .clone
convertedMat = mat;
return true;
}
Schließlich implementiert diese Beispielhilfsklasse eine einzelne Bildverarbeitungsmethode, Blur, die einfach die oben definierte TryConvert--Methode verwendet, um ein Mat-Objekt abzurufen, das die Quellbitmap und die Zielbitmap für den Weichzeichnervorgang darstellt, und ruft dann die Weichzeichner--Methode aus der OpenCV ImgProc-Bibliothek auf. Der andere Parameter zum Weichzeichnen gibt die Größe des Weichzeichnereffekts in den X- und Y-Richtungen an.
void OpenCVHelper::Blur(SoftwareBitmap^ input, SoftwareBitmap^ output)
{
Mat inputMat, outputMat;
if (!(TryConvert(input, inputMat) && TryConvert(output, outputMat)))
{
return;
}
blur(inputMat, outputMat, cv::Size(15, 15));
}
Ein einfaches SoftwareBitmap-OpenCV-Beispiel unter Verwendung der Hilfskomponente.
Nachdem die OpenCVBridge-Komponente erstellt wurde, können wir eine einfache C#-App erstellen, die die OpenCV--Blur--Methode verwendet, um ein SoftwareBitmapzu modifizieren. Um über Ihre UWP-App auf die Komponente für Windows-Runtime zuzugreifen, müssen Sie zuerst einen Verweis auf die Komponente hinzufügen. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Knoten Verweise Unter Ihrem UWP-App-Projekt, und wählen Sie Verweis hinzufügen...aus. Wählen Sie im Dialogfeld "Verweis-Manager" Projektmappe>Projektmappen-aus. Aktivieren Sie das Kontrollkästchen neben dem OpenCVBridge-Projekt, und klicken Sie auf OK.
Im folgenden Beispielcode kann der Benutzer eine Bilddatei auswählen und dann BitmapDecoder- verwenden, um eine SoftwareBitmap- Darstellung des Bilds zu erstellen. Weitere Informationen zum Arbeiten mit SoftwareBitmap-finden Sie unter Erstellen, Bearbeiten und Speichern von Bitmapbildern.
Wie bereits in diesem Artikel beschrieben, erfordert die OpenCVHelper- Klasse, dass alle bereitgestellten SoftwareBitmap- Bilder mit dem BGRA8-Pixelformat mit prämultiplizierten Alphawerten codiert werden. Wenn das Bild also noch nicht in diesem Format enthalten ist, ruft der Beispielcode Convert auf, um das Bild in das erwartete Format zu konvertieren.
Als Nächstes wird eine SoftwareBitmap- erstellt, die als Ziel des Weichzeichnervorgangs verwendet werden soll. Die Eingabebildeigenschaften werden als Argumente für den Konstruktor verwendet, um eine Bitmap mit übereinstimmendem Format zu erstellen.
Es wird eine neue Instanz von OpenCVHelper erstellt, und die Blur--Methode wird aufgerufen, wobei die Quell- und Zielbitmaps übergeben werden. Schließlich wird ein SoftwareBitmapSource- erstellt, um das Ausgabebild einem XAML-Image--Steuerelement zuzuweisen.
Dieser Beispielcode verwendet APIs aus den folgenden Namespaces zusätzlich zu den Namespaces, die in der Standardprojektvorlage enthalten sind.
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media.Imaging;
FileOpenPicker fileOpenPicker = new FileOpenPicker();
fileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
fileOpenPicker.FileTypeFilter.Add(".jpg");
fileOpenPicker.ViewMode = PickerViewMode.Thumbnail;
var inputFile = await fileOpenPicker.PickSingleFileAsync();
if (inputFile == null)
{
// The user cancelled the picking operation
return;
}
SoftwareBitmap inputBitmap;
using (IRandomAccessStream stream = await inputFile.OpenAsync(FileAccessMode.Read))
{
// Create the decoder from the stream
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
// Get the SoftwareBitmap representation of the file
inputBitmap = await decoder.GetSoftwareBitmapAsync();
}
if (inputBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8
|| inputBitmap.BitmapAlphaMode != BitmapAlphaMode.Premultiplied)
{
inputBitmap = SoftwareBitmap.Convert(inputBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}
SoftwareBitmap outputBitmap = new SoftwareBitmap(inputBitmap.BitmapPixelFormat, inputBitmap.PixelWidth, inputBitmap.PixelHeight, BitmapAlphaMode.Premultiplied);
var helper = new OpenCVBridge.OpenCVHelper();
helper.Blur(inputBitmap, outputBitmap);
var bitmapSource = new SoftwareBitmapSource();
await bitmapSource.SetBitmapAsync(outputBitmap);
imageControl.Source = bitmapSource;
Zugehörige Themen