Sequência de fotos variável

Este artigo mostra como capturar uma sequência de fotos variável que permite que você capture vários quadros de imagem em sucessão rápida e configure cada quadro para usar diferentes configurações de foco, flash, ISO, exposição e compensação de exposição. Esse recurso habilita cenários como criar imagens em HDR (High Dynamic Range).

Se você deseja capturar imagens em HDR, mas não deseja implementar seu próprio algoritmo de processamento, use a API AdvancedPhotoCapture para utilizar os recursos HDR nativos do Windows. Para obter mais informações, consulte Captura de fotos em HDR (High Dynamic Range).

Observação

Este artigo se baseia em conceitos e códigos discutidos em Captura básica de fotos, áudio e vídeo com o MediaCapture, que descreve as etapas para implementar uma captura básica de fotos e vídeos. É recomendável que você se familiarize com o padrão de captura de mídia básica neste artigo antes de passar para cenários de captura mais avançados. O código neste artigo presume que seu aplicativo já tenha uma instância de MediaCapture inicializada corretamente.

Configurar seu aplicativo para usar a captura de sequência de fotos variável

Além dos namespaces necessários para captura de mídia básica, implementar uma captura de sequência de fotos variável exige os namespaces a seguir.

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

Declare uma variável de membro para armazenar o objeto VariablePhotoSequenceCapture, que é usado para iniciar a captura de sequência de fotos. Declare uma matriz de objetos SoftwareBitmap para armazenar cada imagem capturada na sequência. Além disso, declare uma matriz para armazenar o objeto CapturedFrameControlValues para cada quadro. Isso pode ser usado pelo seu algoritmo de processamento de imagem para determinar quais configurações foram usadas para capturar cada quadro. Por fim, declare um índice que será usado para controlar a imagem que está sendo capturada na sequência.

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

Preparar a captura de sequência de fotos variável

Depois de iniciar seu MediaCapture, confira se as sequências de fotos variáveis têm suporte no dispositivo atual por meio da obtenção de uma instância do VariablePhotoSequenceController a partir do VideoDeviceController da captura de mídia e da verificação da propriedade Supported.

var varPhotoSeqController = _mediaCapture.VideoDeviceController.VariablePhotoSequenceController;

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

Obtenha um objeto FrameControlCapabilities a partir do controlador de sequência de fotos variável. Esse objeto tem uma propriedade para cada configuração que pode ser definida por quadro de uma sequência de fotos. Estão incluídos:

Este exemplo definirá um valor de compensação de exposição diferente para cada quadro. Para verificar se a compensação de exposição tem suporte para sequências de fotos no dispositivo atual, verifique a propriedade Supported do objeto FrameExposureCompensationCapabilities acessado por meio da propriedade ExposureCompensation.

var frameCapabilities = varPhotoSeqController.FrameCapabilities;

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

Crie um novo objeto FrameController para cada quadro que você deseja capturar. Este exemplo captura três quadros. Defina os valores para os controles que você deseja variar para cada quadro. Em seguida, desmarque a coleção DesiredFrameControllers do VariablePhotoSequenceController e adicione o controlador de cada quadro à coleção.

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

Crie um objeto ImageEncodingProperties para definir a codificação que você deseja usar para as imagens capturadas. Chame o método estático MediaCapture.PrepareVariablePhotoSequenceCaptureAsync, por meio da transmissão das propriedades codificadas. Este método retorna um objeto VariablePhotoSequenceCapture. Por fim, registre manipuladores de eventos para os eventos 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);
}

Iniciar a captura de sequência de fotos variável

Para iniciar a captura de sequência de fotos variável, chame VariablePhotoSequenceCapture.StartAsync. Assegure-se de inicializar as matrizes para armazenar os valores de controle de quadro e as imagens capturadas. Defina o índice atual como 0. Defina a variável de estado de gravação de seu aplicativo e atualize sua interface do usuário para desabilitar a inicialização de outra captura enquanto uma captura está em andamento.

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

    await _photoSequenceCapture.StartAsync();
}

Receber os quadros capturados

O evento PhotoCaptured é gerado para cada quadro capturado. Salve os valores de controle de quadro e a imagem capturada do quadro. Em seguida, incremente o índice de quadro atual. Este exemplo mostra como obter uma representação SoftwareBitmap de cada quadro. Para obter mais informações sobre o uso de SoftwareBitmap, consulte Geração de imagens.

void OnPhotoCaptured(VariablePhotoSequenceCapture s, VariablePhotoCapturedEventArgs args)
{

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

Manipular a conclusão da captura de sequência de fotos variável

O evento Stopped é gerado quando todos os quadros na sequência forem capturados. Atualize o estado de gravação do seu aplicativo e sua interface do usuário para permitir que o usuário inicie novas capturas. Nesse ponto, você pode passar os valores de controle de quadro e as imagens capturadas a seu código de processamento de imagem.

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

Atualizar controladores de quadro

Se você deseja executar outra captura de sequência de fotos variável com diferentes configurações por quadro, não é necessário reinicializar a VariablePhotoSequenceCapture. Você pode desmarcar a coleção DesiredFrameControllers e adicionar novos controladores de quadro ou pode modificar os valores de controlador de quadro existentes. Os exemplos a seguir conferem o objeto FrameFlashCapabilities para verificar se o dispositivo atual suporta energia flash e flash para quadros de sequência de fotos variável. Nesse caso, cada quadro é atualizado para habilitar o flash em 100% de energia. Os valores de compensação de exposição que já foram definidos para cada quadro ainda estão ativos.

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

Desmarcar a captura de sequência de fotos variável

Quando você terminar de capturar as sequências de fotos variáveis ou seu aplicativo estiver suspenso, desmarque o objeto da sequência de fotos variável. Basta chamar FinishAsync. Cancele o registro de manipuladores de evento do objeto e defina-o como null.

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