Переменная последовательность фотографий

В данной статье рассказывается, как захватить переменную последовательность фотографий (то есть несколько снимков, быстро идущих один за другим) и настроить для каждого снимка различные параметры фокусировки, вспышки, ISO, экспозиции и коррекции экспозиции. Эта функция позволяет использовать такие сценарии, как создание изображений с помощью технологии High Dynamic Range (HDR).

Если вам необходимо захватывать изображения с использованием технологии HDR, но вы не хотите создавать собственный алгоритм обработки, вы можете применять API AdvancedPhotoCapture, чтобы использовать встроенные в ОС Windows возможности HDR. Дополнительные сведения см. в статье Захват фотографий с использованием технологии High Dynamic Range (HDR).

Примечание

В этой статье используются понятия и код из статьи Основные принципы фото-, аудио- и видеозахвата с помощью MediaCapture, в которой описаны этапы реализации основных принципов фото- и видеозахвата. Мы рекомендуем ознакомиться с базовым шаблоном захвата мультимедиа в этой статье, прежде чем перейти к более сложным сценариям захвата. Код в этой статье подразумевает, что ваше приложение уже содержит экземпляр MediaCapture, инициализированный надлежащим образом.

Настройка приложения для захвата переменной последовательности фотографий

Помимо пространств имен, необходимых для основных функций захвата мультимедиа, для реализации функции захвата переменной последовательности фотографий необходимы указанные ниже пространства имен.

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

Объявите переменную-член для хранения объекта VariablePhotoSequenceCapture, который используется для инициализации функции захвата последовательности фотографий. Объявите массив объектов SoftwareBitmap для хранения каждого захваченного изображения в последовательности. Кроме того, объявите массив для хранения объекта CapturedFrameControlValues для каждого кадра. Он может использоваться в вашем алгоритме обработки изображений для определения того, какие параметры были использованы для захвата каждого кадра. И, наконец, объявите индекс, который будет использоваться для отслеживания того, какое изображение в последовательности захватывается в данный момент.

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

Подготовка к захвату переменной последовательности фотографий

После успешной инициализации MediaCapture убедитесь, что текущее устройство поддерживает захват переменных последовательностей фотографий. Для этого получите экземпляр VariablePhotoSequenceController из объекта VideoDeviceController для захвата мультимедиа и проверьте свойство Supported.

var varPhotoSeqController = _mediaCapture.VideoDeviceController.VariablePhotoSequenceController;

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

Получите объект FrameControlCapabilities из контроллера переменной последовательности фотографий. У этого объекта имеется свойство для каждого параметра, который можно настроить для каждого кадра в последовательности фотографий. К ним относятся следующие объекты.

В этом примере показано, как настроить разные значения коррекции экспозиции для каждого кадра. Чтобы убедиться, что функция коррекции экспозиции поддерживается для последовательности фотографий в текущем устройстве, проверьте свойство Supported объекта FrameExposureCompensationCapabilities, к которому можно получить доступ с помощью свойства ExposureCompensation.

var frameCapabilities = varPhotoSeqController.FrameCapabilities;

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

Создайте объект FrameController для каждого кадра, который необходимо захватить. В этом примере выполняется захват трех кадров. Задайте значения для элементов управления, которые необходимо изменять для каждого кадра. Затем очистите коллекцию DesiredFrameControllers объекта VariablePhotoSequenceController и добавьте в коллекцию контроллер каждого кадра.

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

Создайте объект ImageEncodingProperties, чтобы настроить кодировку, которую необходимо использовать для захваченных изображений. Вызовите статический метод MediaCapture.PrepareVariablePhotoSequenceCaptureAsync, передав ему свойства кодирования. Этот метод возвращает объект VariablePhotoSequenceCapture. И, наконец, зарегистрируйте обработчики событий PhotoCaptured и 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);
}

Запуск захвата переменной последовательности фотографий

Чтобы запустить захват переменной последовательности фотографий, вызовите метод VariablePhotoSequenceCapture.StartAsync. Обязательно инициализируйте массивы для хранения захваченных изображений и значений элемента управления для работы с кадрами и присвойте текущему индексу значение 0. В приложении настройте переменную состояния записи и обновите пользовательский интерфейс, чтобы в процессе захвата невозможно было запустить еще одну операцию захвата.

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

    await _photoSequenceCapture.StartAsync();
}

Получение захваченных кадров

Для каждого захваченного кадра создается событие PhotoCaptured. Сохраните значения элемента управления для работы с кадрами и захваченное изображение для кадра, а затем увеличьте текущий индекс кадра на единицу. В этом примере показано, как получить представление SoftwareBitmap для каждого кадра. Дополнительные сведения об использовании SoftwareBitmap см. в статье Обработка изображений.

void OnPhotoCaptured(VariablePhotoSequenceCapture s, VariablePhotoCapturedEventArgs args)
{

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

Обработка завершения захвата переменной последовательности фотографий

После захвата всех кадров последовательности создается событие Stopped. Обновите состояние записи вашего приложения и пользовательский интерфейс, чтобы пользователь мог инициировать новые операции захвата. На этом этапе можно передать захваченные изображения и значения элемента управления для работы с кадрами в код обработки изображений.

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

Обновление контроллеров кадров

Если вам необходимо захватить еще одну переменную последовательность фотографий с различными параметрами для каждого кадра, то нет необходимости выполнять полную повторную инициализацию VariablePhotoSequenceCapture. Достаточно либо очистить коллекцию DesiredFrameControllers и добавить новые контроллеры кадров, либо изменить существующие значения контроллера кадра. В примере ниже показано, как проверить объект FrameFlashCapabilities, чтобы убедиться, что текущее устройство поддерживает вспышку и управление ее мощностью для кадров переменной последовательности фотографий. Если это так, то каждый кадр будет обновлен, чтобы использовать вспышку на 100 % ее мощности. Значения коррекции экспозиции, ранее установленные для каждого кадра, будут по-прежнему активными.

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

Очистка захвата переменной последовательности фотографий

После окончания захвата переменных последовательностей фотографий или в случае приостановки вашего приложения очистите объект переменной последовательности фотографий, вызвав метод FinishAsync. Отмените регистрацию обработчиков событий для объекта и присвойте ему значение null.

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