변수 사진 시퀀스

이 문서에서는 변수 사진 시퀀스를 캡처하는 방법을 설명합니다. 이를 통해 여러 이미지 프레임을 연속으로 빠르게 캡처하고 각 프레임에서 다양한 초점, 플래시, ISO, 노출 및 노출 보정 설정을 사용하도록 구성할 수 있습니다. 이 기능을 사용해 HDR(High Dynamic Range) 이미지 만들기 같은 시나리오를 사용할 수 있습니다.

HDR 이미지를 캡처하되, 고유한 처리 알고리즘을 구현하지 않으려면 AdvancedPhotoCapture API를 사용하여 Windows에 기본 제공되는 HDR 기능을 사용하면 됩니다. 자세한 내용은 HDR(High Dynamic Range) 사진 캡처를 참조하세요.

참고 항목

이 문서는 기본 사진 및 비디오 캡처 구현 단계를 설명하는 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 개체를 만듭니다. 이 예제에서는 프레임 세 개를 캡처합니다. 각 프레임마다 변경할 컨트롤의 값을 설정합니다. 그런 다음 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 개체를 반환합니다. 마지막으로 PhotoCapturedStopped 이벤트에 해당하는 이벤트 처리기를 등록합니다.

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;