可变照片序列
本文向你演示如何捕获可变照片序列,允许你快速连续捕获图像的多个帧,并将每个帧配置为使用不同的焦点、闪光灯、ISO、曝光和曝光补偿设置。 此功能启用了创建高动态范围 (HDR) 图像等方案。
如果你想要捕获 HDR 图像,但不想要实现你自己的处理算法,你可以使用 AdvancedPhotoCapture API 来使用内置于 Windows 的 HDR 功能。 有关详细信息,请参阅高动态范围 (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 之后,通过从媒体捕获的 VideoDeviceController 获取 VariablePhotoSequenceController 的实例并检查 Supported 属性,确保可变照片序列在当前设备上受支持。
var varPhotoSeqController = _mediaCapture.VideoDeviceController.VariablePhotoSequenceController;
if (!varPhotoSeqController.Supported)
{
ShowMessageToUser("Variable Photo Sequence is not supported");
return;
}
从可变照片序列控制器获取 FrameControlCapabilities 对象。 此对象具有可针对照片序列的每帧配置的每个设置的属性。 其中包括:
此示例将为每个帧设置一个不同的曝光补偿值。 若要验证照片序列的曝光补偿在当前设备上是否受支持,请检查通过 ExposureCompensation 属性访问的 FrameExposureCompensationCapabilities 对象的 Supported 属性。
var frameCapabilities = varPhotoSeqController.FrameCapabilities;
if (!frameCapabilities.ExposureCompensation.Supported)
{
ShowMessageToUser("EVCompenstaion is not supported in FrameController");
return;
}
为要捕获的每个帧创建一个新的 FrameController 对象。 此示例将捕获三个帧。 为你希望针对每个帧而变化的控件设置值。 接着,清除 VariablePhotoSequenceController 的 DesiredFrameControllers 集合,然后将每个帧控制器添加到该集合。
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。 设置你的应用的录制状态变量并更新你的 UI,以禁止在执行此捕获时启动另一个捕获。
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 事件。 更新你的应用的录制状态并更新你的 UI,以允许用户启动新的捕获。 此时,你可以将捕获的图像和帧控件值传递给图像处理代码。
void OnStopped(object s, object e)
{
_isRecording = false;
MyPostProcessingFunction(_images, _frameControlValues, 3);
}
更新帧控制器
如果你想要使用不同的每帧设置执行另一个可变照片序列捕获,无需完全重新初始化 VariablePhotoSequenceCapture。 你可以清除 DesiredFrameControllers 集合并添加新的帧控制器,也可以修改现有的帧控制器值。 以下示例将检查 FrameFlashCapabilities 对象,以验证当前设备是否支持可变照片序列帧的闪光灯和闪光电源。 如果支持,将更新每个帧,以便在电源已满时启用闪光灯。 之前为每个帧设置的曝光补偿值仍然处于活动状态。
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;
相关主题