Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo illustra come usare la classe
Gli esempi in questo articolo illustrano come creare un componente Windows Runtime di codice nativo che può essere usato da un'app UWP, incluse le app create con C#. Questo componente helper esporrà un singolo metodo, Blur, che userà la funzione di sfocatura dell'immagine di OpenCV. Il componente implementa metodi privati che permettono di ottenere un puntatore al buffer di dati immagine sottostante, utilizzabile direttamente dalla libreria OpenCV, rendendo più semplice estendere il componente di supporto per implementare ulteriori funzionalità di elaborazione con OpenCV.
- Per un'introduzione all'uso di SoftwareBitmap, vedere Creare, modificare e salvare immagini bitmap.
- Per informazioni su come usare la libreria OpenCV, passare a https://opencv.org.
- Per informazioni su come usare il componente helper OpenCV mostrato in questo articolo con MediaFrameReader per implementare l'elaborazione delle immagini in tempo reale dei fotogrammi acquisiti da una fotocamera, vedere Usare OpenCV con MediaFrameReader.
- Per un esempio di codice completo che implementa alcuni effetti diversi, vedi l'esempio Camera Frames + OpenCV nel repository GitHub degli esempi universali di Windows.
Annotazioni
La tecnica usata dal componente OpenCVHelper, descritta in dettaglio in questo articolo, richiede che i dati dell'immagine vengano elaborati risiedono nella memoria DELLA CPU e non nella memoria GPU. Pertanto, per le API che consentono di richiedere la posizione di memoria delle immagini, ad esempio la classe MediaCapture , è necessario specificare la memoria della CPU.
Creare un componente Windows Runtime helper per l'interoperabilità OpenCV
1. Aggiungere un nuovo progetto di componente Windows Runtime di codice nativo alla soluzione
- Aggiungere un nuovo progetto alla soluzione in Visual Studio facendo clic con il pulsante destro del mouse sulla soluzione in Esplora soluzioni e selezionando Aggiungi>Nuovo progetto.
- Nella categoria Visual C++, selezionare Componente Windows Runtime (Universal Windows). Per questo esempio, denominare il progetto "OpenCVBridge" e fare clic su OK.
- Nella finestra di dialogo Nuovo progetto universale di Windows, selezionare la versione di sistema operativo di destinazione e minima per l'app e fare clic su OK.
- Fare clic con il pulsante destro del mouse sul file generato automaticamente Class1.cpp in Esplora soluzioni e scegliere Rimuovi, quando viene visualizzata la finestra di dialogo di conferma, scegliere Elimina. Eliminare quindi il file di intestazione Class1.h.
- Fare clic con il pulsante destro del mouse sull'icona del progetto OpenCVBridge e selezionare
Aggiungi- . Nella finestra di dialogo Aggiungi classeClasse... immettere "OpenCVHelper" nel campo Nome classe e quindi fare clic su OK . Il codice verrà aggiunto ai file di classe creati in un passaggio successivo.
2. Aggiungere i pacchetti NuGet OpenCV al progetto del componente
- Fare clic con il pulsante destro del mouse sull'icona del progetto OpenCVBridge in Esplora soluzioni e scegliere Gestisci pacchetti NuGet...
- Quando si apre la finestra di dialogo "Gestione pacchetti NuGet", selezionare la scheda Sfoglia e digitare "OpenCV.Win" nella casella di ricerca.
- Seleziona "OpenCV.Win.Core" e fai clic su Installa. Nella finestra di dialogo anteprima, fare clic su OK.
- Usare la stessa procedura per installare il pacchetto "OpenCV.Win.ImgProc".
Annotazioni
OpenCV.Win.Core e OpenCV.Win.ImgProc non vengono aggiornati regolarmente e non superano i controlli di conformità dello Store, pertanto questi pacchetti sono destinati solo alla sperimentazione.
3. Implementare la classe OpenCVHelper
Incollare il codice seguente nel file di intestazione OpenCVHelper.h. Questo codice include i file di intestazione OpenCV dei pacchetti Core e ImgProc che abbiamo installato e dichiara tre metodi che verranno mostrati nei passaggi seguenti.
#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);
};
}
Eliminare il contenuto esistente del file OpenCVHelper.cpp e quindi aggiungere le direttive di inclusione seguenti.
#include "pch.h"
#include "OpenCVHelper.h"
#include "MemoryBuffer.h"
Dopo le direttive di inclusione, aggiungere le seguenti usando le direttive.
using namespace OpenCVBridge;
using namespace Platform;
using namespace Windows::Graphics::Imaging;
using namespace Windows::Foundation;
using namespace Microsoft::WRL;
using namespace cv;
Aggiungere quindi il metodo GetPointerToPixelData a OpenCVHelper.cpp. Questo metodo accetta un SoftwareBitmap e, tramite una serie di conversioni, ottiene una rappresentazione dell'interfaccia COM dei dati dei pixel attraverso la quale è possibile ottenere un puntatore al buffer di dati sottostante sotto forma di un array di char .
Prima di tutto, un BitmapBuffer contenente i dati pixel viene ottenuto chiamando LockBuffer, richiedendo un buffer di lettura/scrittura in modo che la libreria OpenCV possa modificare tali dati pixel.
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;
}
Aggiungere quindi il metodo TryConvert illustrato di seguito. Questo metodo accetta un SoftwareBitmap e tenta di convertirlo in un oggetto Mat, che è l'oggetto matrice usato da OpenCV per rappresentare buffer di dati immagine. Questo metodo chiama il metodo GetPointerToPixelData definito in precedenza per ottenere una rappresentazione di array char del buffer di dati pixel. Se l'operazione ha esito positivo, viene chiamato il costruttore per la classe Mat, passando la larghezza e l'altezza dei pixel ottenuta dall'oggetto SoftwareBitmap di origine.
Annotazioni
In questo esempio viene specificata la costante CV_8UC4 come formato pixel per l'oggetto Mat creato. Ciò significa che il
Una copia superficiale dell'oggetto Mat creato viene restituita dal metodo in modo che un'ulteriore elaborazione funzioni sullo stesso buffer di dati pixel a cui fa riferimento il SoftwareBitmap e non una copia del buffer.
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;
}
Infine, questa classe helper di esempio implementa un singolo metodo di elaborazione delle immagini, Blur, che usa semplicemente il metodo TryConvert definito in precedenza per recuperare un oggetto Mat che rappresenta la bitmap di origine e la bitmap di destinazione per l'operazione di sfocatura e quindi chiama il metodo sfocatura dalla libreria ImgProc OpenCV. L'altro parametro di sfocatura specifica la dimensione dell'effetto sfocatura nelle direzioni X e Y.
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));
}
Un semplice esempio di SoftwareBitmap con OpenCV usando il componente di supporto
Ora che il componente OpenCVBridge è stato creato, è possibile creare una semplice app C# che usa il metodo OpenCV sfocatura per modificare un SoftwareBitmap. Per accedere al componente Windows Runtime dall'app UWP, devi prima aggiungere un riferimento al componente. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo Riferimenti nel progetto dell'app UWP e selezionare Aggiungi riferimento. Nella finestra di dialogo Gestione riferimenti selezionare Projects->Solution. Seleziona la casella accanto al progetto OpenCVBridge e fai clic su OK.
Il codice di esempio seguente consente all'utente di selezionare un file di immagine e quindi usa BitmapDecoder per creare una rappresentazione dell'immagine con SoftwareBitmap. Per altre informazioni sull'uso di SoftwareBitmap, vedere Creare, modificare e salvare immagini bitmap.
Come illustrato in precedenza in questo articolo, la classe OpenCVHelper richiede che tutte le immagini SoftwareBitmap fornite vengano codificate usando il formato di pixel BGRA8 con valori alfa premoltiplicati, quindi se l'immagine non è già in questo formato, il codice di esempio chiama Convert per convertire l'immagine nel formato previsto.
Successivamente, viene creato un SoftwareBitmap da usare come obiettivo dell'operazione di sfocatura. Le proprietà dell'immagine di input vengono usate come argomenti per il costruttore per creare una bitmap con formato corrispondente.
Viene creata una nuova istanza di OpenCVHelper e viene chiamato il metodo Blur, passando le bitmap di origine e di destinazione. Infine, viene creato un SoftwareBitmapSource per assegnare l'immagine di output a un controllo XAML Immagine.
Questo codice di esempio usa le API degli spazi dei nomi seguenti, oltre agli spazi dei nomi inclusi nel modello di progetto predefinito.
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;
Argomenti correlati