次の方法で共有


可変の写真シーケンス

この記事では、可変の写真シーケンスをキャプチャする方法について説明します。これによって、画像を複数のフレームとして次々とキャプチャし、各フレームに別々のフォーカス、フラッシュ、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 を初期化した後は、可変の写真シーケンスが現在のデバイスでサポートされていることを確認します。そのためには、VariablePhotoSequenceController のインスタンスをメディア キャプチャの VideoDeviceController から取得し、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 オブジェクトを作成します。 この例では、3 つのフレームをキャプチャします。 フレームごとに変更するコントロールの値を設定します。 次に、VariablePhotoSequenceControllerDesiredFrameControllers コレクションをクリアし、コレクションに各フレーム コントローラーを追加します。

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 オブジェクトを調べて、現在のデバイスが可変の写真シーケンス フレームに対してフラッシュとフラッシュの電源をサポートしているかどうかを確認します。 サポートしている場合は、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;