Sequenza di foto variabile

Questo articolo mostra come acquisire una sequenza di foto variabile, che consente di acquisire più fotogrammi di immagini in rapida successione e configurare ogni fotogramma per usare impostazioni di messa a fuoco, flash, ISO, esposizione e compensazione di esposizione diverse. Questa funzionalità abilita scenari come la creazione di immagini HDR (High Dynamic Range).

Se si desidera acquisire immagini HDR ma non si desidera implementare un algoritmo di elaborazione personalizzato, è possibile usare l'API AdvancedPhotoCapture per usare le funzionalità HDR predefinite in Windows. Per altre informazioni, vedere Acquisizione di foto HDR (High Dynamic Range).

Nota

Questo articolo si basa sui concetti e sul codice descritti in Acquisizione di foto, video e audio di base con MediaCapture, che descrive i passaggi necessari per implementare l'acquisizione di foto e video di base. È consigliabile acquisire familiarità con il modello di acquisizione multimediale di base in questo articolo prima di passare a scenari di acquisizione più avanzati. Il codice in questo articolo presuppone che l'app abbia già un'istanza di MediaCapture che è stata inizializzata correttamente.

Configurare l'app per l'uso dell'acquisizione di sequenze di foto variabili

Oltre agli spazi dei nomi necessari per l'acquisizione multimediale di base, l'implementazione di un'acquisizione di sequenza di foto variabile richiede gli spazi dei nomi seguenti.

using Windows.Media.Capture.Core;
using Windows.Media.Devices.Core;

Dichiarare una variabile membro per archiviare l'oggetto VariablePhotoSequenceCapture, che viene usato per avviare l'acquisizione della sequenza di foto. Dichiarare una matrice di oggetti SoftwareBitmap per archiviare ogni immagine acquisita nella sequenza. Dichiarare anche una matrice per archiviare l'oggetto CapturedFrameControlValues per ogni frame. Questa operazione può essere usata dall'algoritmo di elaborazione delle immagini per determinare quali impostazioni sono state usate per acquisire ogni fotogramma. Infine, dichiarare un indice che verrà usato per tenere traccia dell'immagine nella sequenza attualmente in fase di acquisizione.

VariablePhotoSequenceCapture _photoSequenceCapture;
SoftwareBitmap[] _images;
CapturedFrameControlValues[] _frameControlValues;
int _photoIndex;

Preparare l'acquisizione della sequenza di foto variabile

Dopo aver inizializzato MediaCapture, assicurarsi che le sequenze di foto variabili siano supportate nel dispositivo corrente recuperando un'istanza di VariablePhotoSequenceController dall'acquisizione multimediale VideoDeviceController e controllando la proprietà Supported.

var varPhotoSeqController = _mediaCapture.VideoDeviceController.VariablePhotoSequenceController;

if (!varPhotoSeqController.Supported)
{
    ShowMessageToUser("Variable Photo Sequence is not supported");
    return;
}

Ottenere un oggetto FrameControlCapabilities dal controller della sequenza di foto variabile. Questo oggetto ha una proprietà per ogni impostazione che può essere configurata per fotogramma in una sequenza di foto. tra cui:

In questo esempio verrà impostato un valore di compensazione dell'esposizione diverso per ogni fotogramma. Per verificare che la compensazione dell'esposizione sia supportata per le sequenze fotografiche nel dispositivo corrente, controllare la proprietà Supported dell'oggetto FrameExposureCompensationCapabilities accessibile tramite la proprietà ExposureCompensation.

var frameCapabilities = varPhotoSeqController.FrameCapabilities;

if (!frameCapabilities.ExposureCompensation.Supported)
{
    ShowMessageToUser("EVCompenstaion is not supported in FrameController");
    return;
}

Creare un nuovo oggetto FrameController per ogni fotogramma da acquisire. In questo esempio vengono acquisiti tre fotogrammi. Impostare i valori per i controlli che si desidera variare per ogni fotogramma. Deselezionare quindi l'insieme DesiredFrameControllers di VariablePhotoSequenceController e aggiungere ogni controller frame alla raccolta.

var frame0 = new FrameController();
var frame1 = new FrameController();
var frame2 = new FrameController();

frame0.ExposureCompensationControl.Value = -1.0f;
frame1.ExposureCompensationControl.Value = 0.0f;
frame2.ExposureCompensationControl.Value = 1.0f;

varPhotoSeqController.DesiredFrameControllers.Clear();
varPhotoSeqController.DesiredFrameControllers.Add(frame0);
varPhotoSeqController.DesiredFrameControllers.Add(frame1);
varPhotoSeqController.DesiredFrameControllers.Add(frame2);

Creare un oggetto ImageEncodingProperties per impostare la codifica da usare per le immagini acquisite. Chiamare il metodo statico MediaCapture.PrepareVariablePhotoSequenceCaptureAsync passando le proprietà di codifica. Questo metodo restituisce un oggetto VariablePhotoSequenceCapture. Registrare infine i gestori eventi per gli eventi PhotoCaptured e Stopped.

try
{
    var imageEncodingProperties = ImageEncodingProperties.CreateJpeg();

    _photoSequenceCapture = await _mediaCapture.PrepareVariablePhotoSequenceCaptureAsync(imageEncodingProperties);

    _photoSequenceCapture.PhotoCaptured += OnPhotoCaptured;
    _photoSequenceCapture.Stopped += OnStopped;
}
catch (Exception ex)
{
    ShowMessageToUser("Exception in PrepareVariablePhotoSequence: " + ex.Message);
}

Avviare l'acquisizione della sequenza di foto variabile

Per avviare l'acquisizione della sequenza di foto variabile, chiamare VariablePhotoSequenceCapture.StartAsync. Assicurarsi di inizializzare le matrici per archiviare le immagini acquisite e i valori del controllo frame e impostare l'indice corrente su 0. Impostare la variabile di stato di registrazione dell'app e aggiornare l'interfaccia utente per disabilitare l'avvio di un'altra acquisizione mentre questa acquisizione è in corso.

private async void StartPhotoCapture()
{
    _images = new SoftwareBitmap[3];
    _frameControlValues = new CapturedFrameControlValues[3];
    _photoIndex = 0;
    _isRecording = true;

    await _photoSequenceCapture.StartAsync();
}

Ricevere i fotogrammi acquisiti

L'evento PhotoCaptured viene generato per ogni fotogramma acquisito. Salvare i valori del controllo frame e l'immagine acquisita per il frame e quindi incrementare l'indice frame corrente. Questo esempio mostra come ottenere una rappresentazione SoftwareBitmap di ogni fotogramma. Per altre informazioni sull'uso di SoftwareBitmap, vedere Imaging.

void OnPhotoCaptured(VariablePhotoSequenceCapture s, VariablePhotoCapturedEventArgs args)
{

    _images[_photoIndex] = args.Frame.SoftwareBitmap;
    _frameControlValues[_photoIndex] = args.CapturedFrameControlValues;
    _photoIndex++;
}

Gestire il completamento dell'acquisizione della sequenza di foto variabile

L'evento Stopped viene generato quando tutti i fotogrammi della sequenza sono stati acquisiti. Aggiornare lo stato di registrazione dell'app e aggiornare l'interfaccia utente per consentire all'utente di avviare nuove acquisizioni. A questo punto, è possibile passare le immagini acquisite e i valori del controllo frame al codice di elaborazione delle immagini.

void OnStopped(object s, object e)
{
    _isRecording = false;
    MyPostProcessingFunction(_images, _frameControlValues, 3);
}

Aggiornare i controller dei frame

Per eseguire un'altra acquisizione di sequenza di foto variabile con impostazioni diverse per fotogramma, non reinizializzare completamente VariablePhotoSequenceCapture. È possibile cancellare l'insieme DesiredFrameControllers e aggiungere nuovi controller di frame oppure modificare i valori del controller frame esistenti. Nell'esempio seguente viene controllato l'oggetto FrameFlashCapabilities per verificare che il dispositivo corrente supporti l'alimentazione flash e flash per fotogrammi di sequenza di foto variabili. In tal caso, ogni fotogramma viene aggiornato per abilitare il flash al 100% di potenza. I valori di compensazione dell'esposizione impostati in precedenza per ogni fotogramma sono ancora attivi.

var varPhotoSeqController = _mediaCapture.VideoDeviceController.VariablePhotoSequenceController;

if (varPhotoSeqController.FrameCapabilities.Flash.Supported &&
    varPhotoSeqController.FrameCapabilities.Flash.PowerSupported)
{
    for (int i = 0; i < varPhotoSeqController.DesiredFrameControllers.Count; i++)
    {
        varPhotoSeqController.DesiredFrameControllers[i].FlashControl.Mode = FrameFlashMode.Enable;
        varPhotoSeqController.DesiredFrameControllers[i].FlashControl.PowerPercent = 100;
    }
}

Pulire l'acquisizione della sequenza di foto variabile

Al termine dell'acquisizione di sequenze di foto variabili o la sospensione dell'app, pulire l'oggetto sequenza di foto variabile chiamando FinishAsync. Annullare la registrazione dei gestori eventi dell'oggetto e impostarlo su Null.

await _photoSequenceCapture.FinishAsync();
_photoSequenceCapture.PhotoCaptured -= OnPhotoCaptured;
_photoSequenceCapture.Stopped -= OnStopped;
_photoSequenceCapture = null;