Bagikan melalui


Penangkapan foto rentang dinamis tinggi (HDR) dan cahaya rendah

Artikel ini menunjukkan kepada Anda cara menggunakan kelas AdvancedPhotoCapture untuk mengambil foto rentang dinamis tinggi (HDR). API ini juga memungkinkan Anda untuk mendapatkan bingkai referensi dari tangkapan HDR sebelum pemrosesan gambar akhir selesai.

Artikel lain yang terkait dengan pengambilan HDR meliputi:

Catatan

Dimulai dengan Windows 10, versi 1709, merekam video dan menggunakan AdvancedPhotoCapture secara bersamaan didukung. Ini tidak didukung di versi sebelumnya. Perubahan ini berarti Anda dapat menyiapkan LowLagMediaRecording dan AdvancedPhotoCapture secara bersamaan. Anda dapat memulai atau menghentikan perekaman video antara panggilan ke MediaCapture.PrepareAdvancedPhotoCaptureAsync dan AdvancedPhotoCapture.FinishAsync. Anda juga dapat memanggil AdvancedPhotoCapture.CaptureAsync saat video direkam. Namun, beberapa skenario AdvancedPhotoCapture , seperti menangkap foto HDR saat merekam video akan menyebabkan beberapa bingkai video diubah oleh pengambilan HDR, menghasilkan pengalaman pengguna yang negatif. Untuk alasan ini, daftar mode yang dikembalikan oleh AdvancedPhotoControl.SupportedModes akan berbeda saat video direkam. Anda harus memeriksa nilai ini segera setelah memulai atau menghentikan perekaman video untuk memastikan bahwa mode yang diinginkan didukung dalam status perekaman video saat ini.

Catatan

Dimulai dengan Windows 10, versi 1709, ketika AdvancedPhotoCapture diatur ke mode HDR, pengaturan properti FlashControl.Enabled diabaikan dan lampu kilat tidak pernah diaktifkan. Untuk mode pengambilan lainnya, jika FlashControl.Enabled, itu akan menimpa pengaturan AdvancedPhotoCapture dan menyebabkan foto normal ditangkap dengan flash. Jika Otomatis diatur ke true, AdvancedPhotoCapture mungkin atau mungkin tidak menggunakan lampu kilat, tergantung pada perilaku default driver kamera untuk kondisi di adegan saat ini. Pada rilis sebelumnya, pengaturan lampu kilat AdvancedPhotoCapture selalu mengambil alih pengaturan FlashControl.Enabled .

Catatan

Artikel ini dibangun berdasarkan konsep dan kode yang dibahas dalam pengambilan foto, video, dan audio Dasar dengan MediaCapture, yang menjelaskan langkah-langkah untuk menerapkan pengambilan foto dan video dasar. Sebaiknya Anda membiasakan diri dengan pola tangkapan media dasar dalam artikel tersebut sebelum beralih ke skenario penangkapan yang lebih canggih. Kode dalam artikel ini mengasumsikan bahwa aplikasi Anda sudah memiliki instans MediaCapture yang telah diinisialisasi dengan benar.

Ada Sampel Windows Universal yang menunjukkan penggunaan kelas AdvancedPhotoCapture yang dapat Anda gunakan untuk melihat API yang digunakan dalam konteks atau sebagai titik awal untuk aplikasi Anda sendiri. Untuk informasi selengkapnya lihat, Sampel Pengambilan Tingkat Lanjut Kamera.

Namespace pengambilan foto tingkat lanjut

Contoh kode dalam artikel ini menggunakan API di namespace berikut selain namespace yang diperlukan untuk pengambilan media dasar.

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

Pengambilan foto HDR

Tentukan apakah pengambilan foto HDR didukung pada perangkat saat ini

Teknik penangkapan HDR yang dijelaskan dalam artikel ini dilakukan menggunakan objek AdvancedPhotoCapture. Tidak semua perangkat mendukung pengambilan HDR dengan AdvancedPhotoCapture. Tentukan apakah perangkat tempat aplikasi Anda sedang berjalan mendukung teknik dengan mendapatkan VideoDeviceController objek MediaCapture lalu mendapatkan properti AdvancedPhotoControl. Periksa koleksi SupportedModes pengontrol perangkat video untuk melihat apakah koleksi tersebut menyertakan AdvancedPhotoMode.Hdr. Jika ya, pengambilan HDR menggunakan AdvancedPhotoCapture didukung.

bool _hdrSupported;
private void IsHdrPhotoSupported()
{
    _hdrSupported = _mediaCapture.VideoDeviceController.AdvancedPhotoControl.SupportedModes.Contains(Windows.Media.Devices.AdvancedPhotoMode.Hdr);
}

Mengonfigurasi dan menyiapkan objek AdvancedPhotoCapture

Karena Anda harus mengakses instans AdvancedPhotoCapture dari beberapa tempat dalam kode Anda, Anda harus mendeklarasikan variabel anggota untuk menyimpan objek.

private AdvancedPhotoCapture _advancedCapture;

Di aplikasi Anda, setelah Anda menginisialisasi objek MediaCapture, buat objek AdvancedPhotoCaptureSettings dan atur mode ke AdvancedPhotoMode.Hdr. Panggil metode Konfigurasi objek AdvancedPhotoControl, melewati objek AdvancedPhotoCaptureSettings yang Anda buat.

Panggil objek MediaCapture's PrepareAdvancedPhotoCaptureAsync, meneruskan objek ImageEncodingProperties yang menentukan jenis pengodean yang harus digunakan tangkapan. Kelas ImageEncodingProperties menyediakan metode statis untuk membuat pengodean gambar yang didukung oleh MediaCapture.

PrepareAdvancedPhotoCaptureAsync mengembalikan objek AdvancedPhotoCapture yang akan Anda gunakan untuk memulai pengambilan foto. Anda dapat menggunakan objek ini untuk mendaftarkan handler untuk OptionalReferencePhotoCaptured dan AllPhotosCaptured yang dibahas nanti dalam artikel ini.

if (_hdrSupported == false) return;

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

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

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

// Register for events published by the AdvancedCapture
_advancedCapture.AllPhotosCaptured += AdvancedCapture_AllPhotosCaptured;
_advancedCapture.OptionalReferencePhotoCaptured += AdvancedCapture_OptionalReferencePhotoCaptured;

Mengambil foto HDR

Ambil foto HDR dengan memanggil metode CaptureAsync objek AdvancedPhotoCapture. Metode ini mengembalikan objek AdvancedCapturedPhoto yang menyediakan foto yang diambil di properti Bingkainya.

try
{

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

    using (var frame = advancedCapturedPhoto.Frame)
    {
        // Read the current orientation of the camera and the capture time
        var photoOrientation = CameraRotationHelper.ConvertSimpleOrientationToPhotoOrientation(
            _rotationHelper.GetCameraCaptureOrientation());
        var fileName = String.Format("SimplePhoto_{0}_HDR.jpg", DateTime.Now.ToString("HHmmss"));
        await SaveCapturedFrameAsync(frame, fileName, photoOrientation);
    }
}
catch (Exception ex)
{
    Debug.WriteLine("Exception when taking an HDR photo: {0}", ex.ToString());
}

Sebagian besar aplikasi fotografi akan ingin mengodekan rotasi foto yang diambil ke dalam file gambar sehingga dapat ditampilkan dengan benar oleh aplikasi dan perangkat lain. Contoh ini menunjukkan penggunaan kelas pembantu CameraRotationHelper untuk menghitung orientasi yang tepat untuk file. Kelas ini dijelaskan dan tercantum secara lengkap dalam artikel Menangani orientasi perangkat dengan MediaCapture.

Metode pembantu SaveCapturedFrameAsync , yang menyimpan gambar ke disk, dibahas nanti di artikel ini.

Mendapatkan bingkai referensi opsional

Proses HDR menangkap beberapa bingkai dan kemudian menyusunnya menjadi satu gambar setelah semua bingkai diambil. Anda bisa mendapatkan akses ke bingkai setelah diambil tetapi sebelum seluruh proses HDR selesai dengan menangani peristiwa OptionalReferencePhotoCaptured. Anda tidak perlu melakukan ini jika Anda hanya tertarik pada hasil foto HDR akhir.

Penting

OpsionalReferencePhotoCaptured tidak dinaikkan pada perangkat yang mendukung HDR perangkat keras dan karenanya tidak menghasilkan bingkai referensi. Aplikasi Anda harus menangani kasus di mana peristiwa ini tidak dinaikkan.

Karena bingkai referensi tiba di luar konteks panggilan ke CaptureAsync, mekanisme disediakan untuk meneruskan informasi konteks ke handler OptionalReferencePhotoCaptured . Pertama, Anda harus memanggil objek yang akan berisi informasi konteks Anda. Nama dan isi objek ini terserah Anda. Contoh ini mendefinisikan objek yang memiliki anggota untuk melacak nama file dan orientasi kamera pengambilan.

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

Buat instans baru objek konteks Anda, isi anggotanya, lalu teruskan ke kelebihan beban CaptureAsync yang menerima objek sebagai parameter.

// Read the current orientation of the camera and the capture time
var photoOrientation = CameraRotationHelper.ConvertSimpleOrientationToPhotoOrientation(
        _rotationHelper.GetCameraCaptureOrientation());
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,
    CaptureOrientation = photoOrientation
};

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

Di penanganan aktivitas OptionalReferencePhotoCaptured, transmisikan properti Konteks objek OptionalReferencePhotoCapturedEventArgs ke kelas objek konteks Anda. Contoh ini memodifikasi nama file untuk membedakan gambar bingkai referensi dari gambar HDR akhir lalu memanggil metode pembantu SaveCapturedFrameAsync untuk menyimpan gambar.

private async void 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);
    }
}

Menerima pemberitahuan ketika semua bingkai telah diambil

Pengambilan foto HDR memiliki dua langkah. Pertama, beberapa bingkai diambil, lalu bingkai diproses menjadi gambar HDR akhir. Anda tidak dapat memulai pengambilan lain saat bingkai HDR sumber masih diambil, tetapi Anda dapat memulai pengambilan setelah semua bingkai diambil tetapi sebelum pasca-pemrosesan HDR selesai. Peristiwa AllPhotosCaptured dimunculkan ketika pengambilan HDR selesai, memberi tahu Anda bahwa Anda dapat memulai pengambilan lain. Skenario umumnya adalah menonaktifkan tombol pengambilan UI Anda saat pengambilan HDR dimulai dan kemudian mengaktifkannya kembali ketika AllPhotosCaptured dinaikkan.

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

Membersihkan objek AdvancedPhotoCapture

Setelah aplikasi Anda selesai menangkap, sebelum membuang objek MediaCapture, Anda harus mematikan objek AdvancedPhotoCapture dengan memanggil FinishAsync dan mengatur variabel anggota Anda ke null.

await _advancedCapture.FinishAsync();
_advancedCapture = null;

Pengambilan foto dengan cahaya rendah

Dimulai dengan Windows 10, versi 1607, AdvancedPhotoCapture dapat digunakan untuk mengambil foto menggunakan algoritma bawaan yang meningkatkan kualitas foto yang diambil dalam pengaturan cahaya rendah. Ketika Anda menggunakan fitur cahaya rendah dari kelas AdvancedPhotoCapture , sistem akan mengevaluasi adegan saat ini dan, jika diperlukan, menerapkan algoritma untuk mengimbangi kondisi cahaya rendah. Jika sistem menentukan bahwa algoritma tidak diperlukan, penangkapan reguler dilakukan sebagai gantinya.

Sebelum menggunakan pengambilan foto dengan cahaya rendah, tentukan apakah perangkat tempat aplikasi Anda saat ini berjalan mendukung teknik dengan mendapatkan VideoDeviceController objek MediaCapture dan kemudian mendapatkan properti AdvancedPhotoControl. Periksa koleksi SupportedModes pengontrol perangkat video untuk melihat apakah itu termasuk AdvancedPhotoMode.LowLight. Jika ya, pengambilan cahaya rendah menggunakan AdvancedPhotoCapture didukung.

bool _lowLightSupported;
_lowLightSupported = 
_mediaCapture.VideoDeviceController.AdvancedPhotoControl.SupportedModes.Contains(Windows.Media.Devices.AdvancedPhotoMode.LowLight);

Selanjutnya, deklarasikan variabel anggota untuk menyimpan objek AdvancedPhotoCapture .

private AdvancedPhotoCapture _advancedCapture;

Di aplikasi Anda, setelah Anda menginisialisasi objek MediaCapture, buat objek AdvancedPhotoCaptureSettings dan atur mode ke AdvancedPhotoMode.LowLight. Panggil metode Konfigurasi objek AdvancedPhotoControl, melewati objek AdvancedPhotoCaptureSettings yang Anda buat.

Panggil objek MediaCapture's PrepareAdvancedPhotoCaptureAsync, meneruskan objek ImageEncodingProperties yang menentukan jenis pengodean yang harus digunakan tangkapan.

if (_lowLightSupported == false) return;

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

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

Untuk mengambil foto, panggil CaptureAsync.

AdvancedCapturedPhoto advancedCapturedPhoto = await _advancedCapture.CaptureAsync();
var photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
var fileName = String.Format("SimplePhoto_{0}_LowLight.jpg", DateTime.Now.ToString("HHmmss"));
await SaveCapturedFrameAsync(advancedCapturedPhoto.Frame, fileName, photoOrientation);

Seperti contoh HDR di atas, contoh ini menggunakan kelas pembantu yang disebut CameraRotationHelper untuk menentukan nilai rotasi yang harus dikodekan ke dalam gambar sehingga dapat ditampilkan dengan benar oleh aplikasi dan perangkat lain. Kelas ini dijelaskan dan tercantum secara lengkap dalam artikel Menangani orientasi perangkat dengan MediaCapture.

Metode pembantu SaveCapturedFrameAsync , yang menyimpan gambar ke disk, dibahas nanti di artikel ini.

Anda dapat mengambil beberapa foto dengan cahaya rendah tanpa mengonfigurasi ulang objek AdvancedPhotoCapture , tetapi ketika Anda selesai menangkap, Anda harus memanggil FinishAsync untuk membersihkan objek dan sumber daya terkait.

await _advancedCapture.FinishAsync();
_advancedCapture = null;

Bekerja dengan objek AdvancedCapturedPhoto

AdvancedPhotoCapture.CaptureAsync mengembalikan objek AdvancedCapturedPhoto yang mewakili foto yang diambil. Objek ini mengekspos properti Bingkai yang mengembalikan objek CapturedFrame yang mewakili gambar. Peristiwa OptionalReferencePhotoCaptured juga menyediakan objek CapturedFrame dalam args peristiwanya. Setelah Anda mendapatkan objek jenis ini, ada sejumlah hal yang dapat Anda lakukan dengannya, termasuk membuat SoftwareBitmap atau menyimpan gambar ke file.

Mendapatkan SoftwareBitmap dari CapturedFrame

Sangat sepele untuk mendapatkan SoftwareBitmap dari objek CapturedFrame hanya dengan mengakses properti SoftwareBitmap objek. Namun, sebagian besar format pengodean tidak mendukung SoftwareBitmap dengan AdvancedPhotoCapture, jadi Anda harus memeriksa dan memastikan properti tidak null sebelum menggunakannya.

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

Dalam rilis saat ini, satu-satunya format pengodean yang mendukung SoftwareBitmap untuk AdvancedPhotoCapture adalah NV12 yang tidak dikompresi. Jadi, jika Anda ingin menggunakan fitur ini, Anda harus menentukan pengodean tersebut saat memanggil PrepareAdvancedPhotoCaptureAsync.

_advancedCapture =
    await _mediaCapture.PrepareAdvancedPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Nv12));

Tentu saja, Anda selalu dapat menyimpan gambar ke file dan kemudian memuat file ke dalam SoftwareBitmap dalam langkah terpisah. Untuk informasi selengkapnya tentang bekerja dengan SoftwareBitmap, lihat Membuat, mengedit, dan menyimpan gambar bitmap.

Menyimpan CapturedFrame ke file

Kelas CapturedFrame mengimplementasikan antarmuka IInputStream, sehingga dapat digunakan sebagai input ke BitmapDecoder, dan kemudian BitmapEncoder dapat digunakan untuk menulis data gambar ke disk.

Dalam contoh berikut, folder baru di pustaka gambar pengguna dibuat dan file dibuat dalam folder ini. Perhatikan bahwa aplikasi Anda harus menyertakan kemampuan Pustaka Gambar dalam file manifes aplikasi Anda untuk mengakses direktori ini. Aliran file kemudian dibuka ke file yang ditentukan. Selanjutnya, BitmapDecoder.CreateAsync dipanggil untuk membuat dekoder dari CapturedFrame. Kemudian CreateForTranscodingAsync membuat encoder dari aliran file dan dekoder.

Langkah selanjutnya mengodekan orientasi foto ke dalam file gambar dengan menggunakan BitmapProperties dari encoder. Untuk informasi selengkapnya tentang menangani orientasi saat menangkap gambar, lihat Menangani orientasi perangkat dengan MediaCapture.

Akhirnya, gambar ditulis ke file dengan panggilan ke FlushAsync.

private static async Task<StorageFile> SaveCapturedFrameAsync(CapturedFrame frame, string fileName, PhotoOrientation photoOrientation)
{
    var folder = await KnownFolders.PicturesLibrary.CreateFolderAsync("MyApp", CreationCollisionOption.OpenIfExists);
    var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);

    using (var inputStream = frame)
    {
        using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            var decoder = await BitmapDecoder.CreateAsync(inputStream);
            var encoder = await BitmapEncoder.CreateForTranscodingAsync(fileStream, decoder);
            var properties = new BitmapPropertySet {
                { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
            await encoder.BitmapProperties.SetPropertiesAsync(properties);
            await encoder.FlushAsync();
        }
    }
    return file;
}