Wysoki zakres dynamiczny (HDR) i przechwytywanie zdjęć o niskim świetle

W tym artykule pokazano, jak używać klasy AdvancedPhotoCapture do przechwytywania zdjęć o wysokim zakresie dynamicznym (HDR). Ten interfejs API umożliwia również uzyskanie ramki referencyjnej z przechwytywania HDR przed zakończeniem przetwarzania obrazu końcowego.

Inne artykuły związane z przechwytywaniem HDR obejmują:

Uwaga / Notatka

Począwszy od systemu Windows 10, wersja 1709, nagrywanie wideo i używanie funkcji AdvancedPhotoCapture współbieżnie jest obsługiwane. Nie jest to obsługiwane w poprzednich wersjach. Ta zmiana oznacza, że możesz mieć jednocześnie przygotowane LowLagMediaRecording i AdvancedPhotoCapture. Możesz uruchomić lub zatrzymać nagrywanie wideo między wywołaniami do pliku MediaCapture.PrepareAdvancedPhotoCaptureAsync i AdvancedPhotoCapture.FinishAsync. Możesz również wywołać metodę AdvancedPhotoCapture.CaptureAsync podczas nagrywania wideo. Jednak niektóre scenariusze AdvancedPhotoCapture , takie jak przechwytywanie zdjęcia HDR podczas nagrywania wideo spowodowałoby zmianę niektórych klatek wideo przez przechwytywanie HDR, co spowodowałoby negatywne wrażenia użytkownika. Z tego powodu lista trybów zwracanych przez element AdvancedPhotoControl.SupportedModes będzie inna podczas nagrywania wideo. Tę wartość należy sprawdzić natychmiast po uruchomieniu lub zatrzymaniu nagrywania wideo, aby upewnić się, że żądany tryb jest obsługiwany w bieżącym stanie nagrywania wideo.

Uwaga / Notatka

Począwszy od systemu Windows 10 w wersji 1709, gdy ustawienie AdvancedPhotoCapture jest ustawione na tryb HDR, ustawienie właściwości FlashControl.Enabled jest ignorowane, a lampa błyskowa nigdy nie jest uruchamiana. W przypadku innych trybów przechwytywania, jeśli flashControl.Enabled, zastąpi ustawienia AdvancedPhotoCapture i spowoduje przechwycenie normalnego zdjęcia z lampą błyskową. Jeśli wartość Auto jest ustawiona na wartość true, funkcja AdvancedPhotoCapture może lub nie może używać lampy błyskowej, w zależności od domyślnego zachowania sterownika aparatu dla warunków w bieżącej scenie. W poprzednich wersjach ustawienie flash AdvancedPhotoCapture zawsze zastępuje ustawienie FlashControl.Enabled .

Istnieje pełny przykład pokazujący użycie klasy AdvancedPhotoCapture , której można użyć do wyświetlenia interfejsu API używanego w kontekście lub jako punktu wyjścia dla własnej aplikacji. Aby uzyskać więcej informacji, zobacz Camera Advanced Capture sample (Przykład zaawansowanego przechwytywania aparatu).

Przechwytywanie zdjęć HDR

Ustal, czy przechwytywanie zdjęć HDR jest obsługiwane na bieżącym urządzeniu

Technika przechwytywania HDR opisana w tym artykule jest wykonywana przy użyciu obiektu AdvancedPhotoCapture . Nie wszystkie urządzenia obsługują przechwytywanie HDR za pomocą funkcji AdvancedPhotoCapture. Ustal, czy urządzenie, na którym aplikacja jest aktualnie uruchomiona, obsługuje technikę, uzyskując właściwość VideoDeviceController obiektu MediaCapture, a następnie uzyskując właściwość AdvancedPhotoControl. Sprawdź kolekcję SupportedModes kontrolera urządzenia wideo, aby sprawdzić, czy zawiera ona element AdvancedPhotoMode.Hdr. Jeśli tak, przechwytywanie HDR przy użyciu advancedPhotoCapture jest obsługiwane.

m_hdrSupported = m_mediaCapture.VideoDeviceController.AdvancedPhotoControl.SupportedModes.Contains(Windows.Media.Devices.AdvancedPhotoMode.Hdr);

Konfigurowanie i przygotowywanie obiektu AdvancedPhotoCapture

Ponieważ musisz uzyskać dostęp do wystąpienia AdvancedPhotoCapture z wielu miejsc w kodzie, należy zadeklarować zmienną składową do przechowywania obiektu.

private AdvancedPhotoCapture m_advancedCapture;

W aplikacji po zainicjowaniu obiektu MediaCapture utwórz obiekt AdvancedPhotoCaptureSettings i ustaw tryb na AdvancedPhotoMode.Hdr. Wywołaj metodę Configure obiektu AdvancedPhotoControl, przekazując utworzony obiekt AdvancedPhotoCaptureSettings.

Wywołaj obiekt MediaCapturePrepareAdvancedPhotoCaptureAsync, przekazując obiekt ImageEncodingProperties określający typ kodowania przechwytywania. Klasa ImageEncodingProperties udostępnia metody statyczne do tworzenia kodowań obrazów obsługiwanych przez aplikację MediaCapture.

Metoda PrepareAdvancedPhotoCaptureAsync zwraca obiekt AdvancedPhotoCapture , którego użyjesz do zainicjowania przechwytywania zdjęć. Tego obiektu można użyć do rejestrowania procedur obsługi dla OptionalReferencePhotoCaptured i AllPhotosCaptured, które zostały omówione w dalszej części tego artykułu.

if (m_hdrSupported == false) return;

// Choose HDR mode
var settings = new AdvancedPhotoCaptureSettings { Mode = AdvancedPhotoMode.Hdr };

// Configure the mode
m_mediaCapture.VideoDeviceController.AdvancedPhotoControl.Configure(settings);

// Prepare for an advanced capture
m_advancedCapture =
    await m_mediaCapture.PrepareAdvancedPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Nv12));

// Register for events published by the AdvancedCapture
m_advancedCapture.AllPhotosCaptured += M_advancedCapture_AllPhotosCaptured;
m_advancedCapture.OptionalReferencePhotoCaptured += M_advancedCapture_OptionalReferencePhotoCaptured;

Przechwytywanie zdjęcia HDR

Przechwyć zdjęcie HDR, wywołując metodę CaptureAsync obiektu AdvancedPhotoCapture. Ta metoda zwraca obiekt AdvancedCapturedPhoto , który udostępnia przechwycone zdjęcie we właściwości Frame . Następnie zdjęcie zostanie zapisane na dysku.

try
{

    // Start capture, and pass the context object
    AdvancedCapturedPhoto advancedCapturedPhoto = await m_advancedCapture.CaptureAsync();

    using (var frame = advancedCapturedPhoto.Frame)
    {
        var fileName = String.Format("SimplePhoto_{0}_HDR.jpg", DateTime.Now.ToString("HHmmss"));
        StorageFile photoFile = await KnownFolders.PicturesLibrary.CreateFileAsync(fileName);
        IRandomAccessStream stream = await photoFile.OpenAsync(FileAccessMode.ReadWrite);
        await RandomAccessStream.CopyAndCloseAsync(advancedCapturedPhoto.Frame, stream);
    }
}
catch (Exception ex)
{
    Debug.WriteLine("Exception when taking an HDR photo: {0}", ex.ToString());
}

Pobierz opcjonalną ramkę referencyjną

Proces HDR przechwytuje wiele ramek, a następnie składa je w jeden obraz po przechwyceniu wszystkich ramek. Dostęp do ramki można uzyskać po jego przechwyceniu, ale zanim cały proces HDR zostanie ukończony, obsługując zdarzenie OptionalReferencePhotoCaptured . Nie musisz tego robić, jeśli interesuje Cię tylko końcowy wynik zdjęcia HDR.

Ważne

Funkcja OptionalReferencePhotoCaptured nie jest wywoływana na urządzeniach obsługujących sprzętOWY format HDR i dlatego nie generuje ramek referencyjnych. Aplikacja powinna obsługiwać przypadek, w którym to zdarzenie nie jest zgłaszane.

Ponieważ ramka referencyjna pojawia się poza kontekstem wywołania CaptureAsync, dostępny jest mechanizm przekazywania informacji kontekstowych do procedury obsługi OptionalReferencePhotoCaptured. Najpierw należy wywołać obiekt, który będzie zawierać informacje kontekstowe. Nazwa i zawartość tego obiektu jest do Ciebie. W tym przykładzie zdefiniowano obiekt, który ma elementy członkowskie do śledzenia nazwy pliku i orientacji kamery podczas przechwytywania.

public class MyAdvancedCaptureContextObject
{
    public string CaptureFileName;
    public PhotoOrientation CaptureOrientation;
}

Utwórz nowe wystąpienie obiektu kontekstu, wypełnij jego elementy członkowskie, a następnie przekaż je do przeciążenia funkcji CaptureAsync , która akceptuje obiekt jako parametr.

// Add the the capture time to the file name
var fileName = String.Format("SimplePhoto_{0}_HDR.jpg", DateTime.Now.ToString("HHmmss"));

// Create a context object, to identify the capture in the OptionalReferencePhotoCaptured event
var context = new MyAdvancedCaptureContextObject()
{
    CaptureFileName = fileName,
};

// Start capture, and pass the context object
AdvancedCapturedPhoto advancedCapturedPhoto = await m_advancedCapture.CaptureAsync(context);

W procedurze obsługi zdarzeń OptionalReferencePhotoCaptured należy rzutować właściwość Context obiektu OptionalReferencePhotoCapturedEventArgs do klasy Twojego obiektu kontekstu. Ten przykład modyfikuje nazwę pliku, aby odróżnić obraz ramki referencyjnej od końcowego obrazu HDR, a następnie zapisuje obraz na dysku.

private async void M_advancedCapture_OptionalReferencePhotoCaptured(AdvancedPhotoCapture sender, OptionalReferencePhotoCapturedEventArgs args)
{
    // Retrieve the context (i.e. what capture does this belong to?)
    var context = args.Context as MyAdvancedCaptureContextObject;

    // Remove "_HDR" from the name of the capture to create the name of the reference
    var referenceName = context.CaptureFileName.Replace("_HDR", "");

    using (var frame = args.Frame)
    {
        await SaveCapturedFrameAsync(frame, referenceName, context.CaptureOrientation);
    }
}

Otrzymuj powiadomienie, gdy wszystkie ramki zostaną przechwycone

Przechwytywanie zdjęć HDR ma dwa kroki. Najpierw przechwytywane są wiele ramek, a następnie ramki są przetwarzane do końcowego obrazu HDR. Nie można zainicjować innego przechwytywania, gdy źródłowe ramki HDR są nadal przechwytywane, ale można zainicjować przechwytywanie po przechwyceniu wszystkich ramek, ale przed zakończeniem przetwarzania końcowego HDR. Zdarzenie AllPhotos Capture jest zgłaszane po zakończeniu przechwytywania HDR, informując o tym, że można zainicjować inne przechwytywanie. Typowy scenariusz polega na wyłączeniu przycisku przechwytywania interfejsu użytkownika, kiedy zostało uruchomione przechwytywanie HDR, a następnie ponownie włączyć go, gdy AllPhotosCaptured jest podnoszone.

private void M_advancedCapture_AllPhotosCaptured(AdvancedPhotoCapture sender, object args)
{
    // Update UI to enable capture button
}

Czyszczenie obiektu AdvancedPhotoCapture

Po zakończeniu przechwytywania aplikacji przed usunięciem obiektu MediaCapture należy zamknąć obiekt AdvancedPhotoCapture , wywołując metodę FinishAsync i ustawiając zmienną składową na null.

await m_advancedCapture.FinishAsync();
m_advancedCapture = null;

Przechwytywanie zdjęć z małą ilością światła

Począwszy od systemu Windows 10, wersja 1607, AdvancedPhotoCapture może służyć do przechwytywania zdjęć przy użyciu wbudowanego algorytmu, który zwiększa jakość zdjęć przechwyconych w ustawieniach o niskiej ilości światła. Jeśli używasz funkcji słabego oświetlenia klasy AdvancedPhotoCapture, system oceni bieżącą scenę i, w razie potrzeby, zastosuje algorytm, aby skompensować brak oświetlenia. Jeśli system ustali, że algorytm nie jest potrzebny, zamiast tego jest wykonywane regularne przechwytywanie.

Przed użyciem przechwytywania zdjęć o niskim świetle określ, czy urządzenie, na którym jest aktualnie uruchomiona aplikacja, obsługuje technikę, uzyskując właściwość VideoDeviceController obiektu MediaCapture, a następnie uzyskując właściwość AdvancedPhotoControl. Sprawdź kolekcję SupportedModes kontrolera urządzenia wideo, aby sprawdzić, czy zawiera element AdvancedPhotoMode.LowLight. Jeśli tak się dzieje, funkcja przechwytywania z małym światłem przy użyciu metody AdvancedPhotoCapture jest obsługiwana.

m_lowLightSupported = m_mediaCapture.VideoDeviceController.AdvancedPhotoControl.SupportedModes.Contains(Windows.Media.Devices.AdvancedPhotoMode.LowLight);

W aplikacji po zainicjowaniu obiektu MediaCapture utwórz obiekt AdvancedPhotoCaptureSettings i ustaw tryb AdvancedPhotoMode.LowLight. Wywołaj metodę Configure obiektu AdvancedPhotoControl, przekazując utworzony obiekt AdvancedPhotoCaptureSettings.

Wywołaj obiekt MediaCapturePrepareAdvancedPhotoCaptureAsync, przekazując obiekt ImageEncodingProperties określający typ kodowania przechwytywania.

if (m_lowLightSupported == false) return;

// Choose LowLight mode
var settings = new AdvancedPhotoCaptureSettings { Mode = AdvancedPhotoMode.LowLight };
m_mediaCapture.VideoDeviceController.AdvancedPhotoControl.Configure(settings);

// Prepare for an advanced capture
m_advancedCapture =
    await m_mediaCapture.PrepareAdvancedPhotoCaptureAsync(ImageEncodingProperties.CreateJpeg());

Aby przechwycić zdjęcie, wywołaj metodę CaptureAsync.

AdvancedCapturedPhoto advancedCapturedPhoto = await m_advancedCapture.CaptureAsync();
StorageFile photoFile = await KnownFolders.PicturesLibrary.CreateFileAsync($"Photo_{advancedCapturedPhoto.Mode}.jpg", CreationCollisionOption.GenerateUniqueName);
IRandomAccessStream stream = await photoFile.OpenAsync(FileAccessMode.ReadWrite);
await RandomAccessStream.CopyAndCloseAsync(advancedCapturedPhoto.Frame, stream);

Można przechwytywać wiele zdjęć o niskim świetle bez ponownej konfiguracji obiektu AdvancedPhotoCapture , ale po zakończeniu przechwytywania należy wywołać metodę FinishAsync , aby wyczyścić obiekt i skojarzone zasoby.

await m_advancedCapture.FinishAsync();
m_advancedCapture = null;

Praca z obiektami AdvancedCapturedPhoto

Funkcja AdvancedPhotoCapture.CaptureAsync zwraca obiekt Advanced CapturePhoto reprezentujący przechwycone zdjęcie. Ten obiekt uwidacznia właściwość Frame , która zwraca obiekt CapturedFrame reprezentujący obraz. Zdarzenie OptionalReferencePhotoCaptured udostępnia również obiekt CapturedFrame w argumentach zdarzenia. Po otrzymaniu obiektu tego typu istnieje wiele czynności, które można z nim zrobić, w tym utworzenie mapy SoftwareBit lub zapisanie obrazu w pliku.

Uzyskaj SoftwareBitmap z CapturedFrame

Pobierz mapę SoftwareBitmap z obiektu CapturedFrame , korzystając po prostu z właściwości SoftwareBitmap obiektu. Jednak większość formatów kodowania nie obsługuje oprogramowania SoftwareBitmap z funkcją AdvancedPhotoCapture, dlatego przed użyciem tej właściwości należy sprawdzić i upewnić się, że właściwość nie ma wartości null.

SoftwareBitmap bitmap;
if (advancedCapturedPhoto.Frame.SoftwareBitmap != null)
{
    bitmap = advancedCapturedPhoto.Frame.SoftwareBitmap;
}

W bieżącej wersji jedynym formatem kodowania obsługującym SoftwareBitmap dla AdvancedPhotoCapture jest nieskompresowany NV12. Dlatego, jeśli chcesz użyć tej funkcji, musisz określić to kodowanie podczas wywoływania PrepareAdvancedPhotoCaptureAsync.

m_advancedCapture =
    await m_mediaCapture.PrepareAdvancedPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Nv12));

Oczywiście zawsze można zapisać obraz w pliku, a następnie załadować go do mapy SoftwareBit w osobnym kroku. Aby uzyskać więcej informacji na temat pracy z rozwiązaniem SoftwareBitmap, zobacz Tworzenie, edytowanie i zapisywanie obrazów map bitowych.