Secuencia de fotos variable

En este artículo se muestra cómo capturar una secuencia de fotos variable, que permite capturar varios fotogramas de imágenes en sucesión rápida y configurar cada uno para que use una configuración de foco, flash, ISO, exposición y compensación de la exposición diferente. Esta característica permite escenarios como crear imágenes de alto rango dinámico (HDR).

Si deseas capturar imágenes HDR pero no quieres implementar tu propio algoritmo de procesamiento, puedes usar la API AdvancedPhotoCapture para usar las funcionalidades HDR integradas en Windows. Para obtener más información, consulta Captura de fotos de alto rango dinámico (HDR).

Nota:

Este artículo se basa en los conceptos y el código analizados en Captura básica de fotos, audio y vídeo con MediaCapture, donde se describen los pasos para implementar la captura básica de fotos y vídeo. Se recomienda que te familiarices con el patrón de captura de multimedia básico de ese artículo antes de pasar a escenarios más avanzados de captura. El código que encontrarás en este artículo se ha agregado suponiendo que la aplicación ya tiene una instancia de MediaCapture inicializada correctamente.

Configurar la aplicación para usar la captura de secuencia de fotos variable

Además de los espacios de nombres necesarios para la captura de multimedia básico, la implementación de una captura de secuencia fotográfica variable requiere los siguientes espacios de nombres.

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

Declara una variable de miembro para almacenar el objeto VariablePhotoSequenceCapture, que se usa para iniciar la captura de secuencia de fotos. Declara una matriz de objetos SoftwareBitmap para almacenar cada imagen capturada en la secuencia. Además, declara una matriz para almacenar el objeto CapturedFrameControlValues por cada fotograma. Puede usarse por su algoritmo de procesamiento de imagen para determinar qué configuración se usó para capturar cada fotograma. Por último, declara un índice que se usará para dar seguimiento a la imagen en la secuencia que se está capturando en el momento.

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

Preparar la captura de secuencia de fotos variable

Después de inicializar tu objeto MediaCapture, asegúrate de que las secuencias de fotos variables son compatibles con el dispositivo actual. Para ello, obtén una instancia del objeto VariablePhotoSequenceController de la captura multimedia VideoDeviceController y comprueba la propiedad Supported.

var varPhotoSeqController = _mediaCapture.VideoDeviceController.VariablePhotoSequenceController;

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

Obtén un objeto FrameControlCapabilities desde el controlador de secuencia fotográfica variable. Este objeto tiene una propiedad para cada configuración que pueda configurarse por fotograma de una secuencia de fotos. Entre ellas se incluyen las siguientes:

En este ejemplo se establece un valor de compensación de la exposición diferente para cada fotograma. Para comprobar que la compensación de la exposición es compatible con secuencias de fotos en el dispositivo actual, comprueba la propiedad Supported del objeto FrameExposureCompensationCapabilities al que se accede a través de la propiedad ExposureCompensation.

var frameCapabilities = varPhotoSeqController.FrameCapabilities;

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

Crea un nuevo objeto FrameController por cada fotograma que quieras capturar. En este ejemplo se capturan tres fotogramas. Establece los valores para los controles que desees variar para cada fotograma. A continuación, borra la colección DesiredFrameControllers de VariablePhotoSequenceController y agrega el controlador de cada fotograma a la colección.

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);

Crea un objeto ImageEncodingProperties para establecer la codificación que desees usar para las imágenes capturadas. Llama al método estático MediaCapture.PrepareVariablePhotoSequenceCaptureAsync y pasa las propiedades de codificación. Este método devuelve un objeto VariablePhotoSequenceCapture. Por último, registra controladores de eventos para los eventos PhotoCaptured y 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);
}

Inicia la captura de una secuencia de fotos variable

Para iniciar la captura de la secuencia de fotos variable, llama a VariablePhotoSequenceCapture.StartAsync. Asegúrate de inicializar las matrices para almacenar las imágenes capturadas y los valores de control de fotograma, y establece el índice actual en 0. Establece la variable de estado de grabación de la aplicación y actualiza la interfaz de usuario para deshabilitar el inicio de otra captura mientras esta está en curso.

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

    await _photoSequenceCapture.StartAsync();
}

Recibe los fotogramas capturados

El evento PhotoCaptured se genera para cada fotograma capturado. Guarda los valores de control y la imagen capturada para el fotograma y, a continuación, incrementa el índice del fotograma actual. Este ejemplo muestra cómo obtener una representación SoftwareBitmap de cada fotograma. Para obtener más información acerca del uso de SoftwareBitmap, consulta Imagen.

void OnPhotoCaptured(VariablePhotoSequenceCapture s, VariablePhotoCapturedEventArgs args)
{

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

Administra la finalización de la captura de secuencia de fotos variable

El evento Stopped se produce cuando todos los fotogramas de la secuencia han sido capturados. Actualizar el estado de grabación de la aplicación y actualizar la interfaz de usuario para permitir al usuario iniciar nuevas capturas. En este punto, puedes pasar las imágenes capturadas y los valores de control de fotograma al código de procesamiento de la imagen.

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

Actualiza los controladores de fotograma

Si deseas realizar otra captura de secuencia de fotos variable con una configuración diferente para cada fotograma, no necesitas reiniciar completamente VariablePhotoSequenceCapture. Puedes borrar la colección DesiredFrameControllers y agregar nuevos controladores de fotograma, o puedes modificar los valores del controlador de fotograma existente. El siguiente ejemplo comprueba el objeto FrameFlashCapabilities para comprobar que el dispositivo actual es compatible con el flash y la potencia del flash para los fotogramas de una secuencia de fotos variable. Si es así, se actualiza cada fotograma para habilitar el flash al 100% de energía. Los valores de compensación de exposición que anteriormente estaban establecidos por cada fotograma siguen activos.

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;
    }
}

Limpia la captura de una secuencia de fotos variable

Cuando hayas terminado de capturar secuencias de fotos variables o la aplicación esté suspendida, limpia el objeto de secuencia de fotos variable con una llamada a FinishAsync. Anula el registro de controladores de eventos del objeto y establécelo en null.

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