毎度のお約束、本記事はプレビュー状態のOS、IDE、SDKを利用しております。製品版では異なる可能性があります。
本記事はWindows 10向けのユニバーサルWindowsアプリについて学んだことを残して行く記事です。
これまでの記事はカテゴリ「UWP(Win 10) Preview」を参照ください。
今回はCameraGetPreviewFrameサンプルを紹介します。
プロジェクト名から予想がつくようにカメラ画像からプレビュー画像を取得して加工や保存します。
Windows 8、8.1時代とはAPIが変わっていて、新しく覚えないといけない感じがします。
プレビュー画像の取得
カメラ映像から画像を取得するにはVideoFrameクラスを取得してSoftwareBitmapを取り出します。
var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties; // Create the video frame to request a SoftwareBitmap preview frame var videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)previewProperties.Width, (int)previewProperties.Height); // Capture the preview frame using (var currentFrame = await _mediaCapture.GetPreviewFrameAsync(videoFrame)) { // Collect the resulting frame SoftwareBitmap previewFrame = currentFrame.SoftwareBitmap; // Show the frame information FrameInfoTextBlock.Text = String.Format("{0}x{1} {2}", previewFrame.PixelWidth, previewFrame.PixelHeight, previewFrame.BitmapPixelFormat); // Add a simple green filter effect to the SoftwareBitmap if (GreenEffectCheckBox.IsChecked == true) { ApplyGreenFilter(previewFrame); } // Show the frame (as is, no rotation is being applied) if (ShowFrameCheckBox.IsChecked == true) { // Create a SoftwareBitmapSource to display the SoftwareBitmap to the user var sbSource = new SoftwareBitmapSource(); await sbSource.SetBitmapAsync(previewFrame); // Display it in the Image control PreviewFrameImage.Source = sbSource; } // Save the frame (as is, no rotation is being applied) if (SaveFrameCheckBox.IsChecked == true) { await SaveSoftwareBitmapAsync(previewFrame); } }
SoftwareBitmapをSoftwareBitmapSourceにセットして、ImageコントロールのSourceに指定しています。
うん見慣れない流れですね。
サンプルでは画像を全体的に緑っぽい色に変換しています。
ちょっと長いですが、SoftwareBitmap型の変数bitmapからCreateReferenceメソッドでストリームを取り出して、それを加工するという流れです。
if (bitmap.BitmapPixelFormat == BitmapPixelFormat.Bgra8) { // In BGRA8 format, each pixel is defined by 4 bytes const int BYTES_PER_PIXEL = 4; using (var buffer = bitmap.LockBuffer(BitmapBufferAccessMode.ReadWrite)) using (var reference = buffer.CreateReference()) { if (reference is IMemoryBufferByteAccess) { // Get a pointer to the pixel buffer byte* data; uint capacity; ((IMemoryBufferByteAccess)reference).GetBuffer(out data, out capacity); // Get information about the BitmapBuffer var desc = buffer.GetPlaneDescription(0); // Iterate over all pixels for (uint row = 0; row < desc.Height; row++) { for (uint col = 0; col < desc.Width; col++) { // Index of the current pixel in the buffer (defined by the next 4 bytes, BGRA8) var currPixel = desc.StartIndex + desc.Stride * row + BYTES_PER_PIXEL * col; // Read the current pixel information into b,g,r channels (leave out alpha channel) var b = data[currPixel + 0]; // Blue var g = data[currPixel + 1]; // Green var r = data[currPixel + 2]; // Red // Boost the green channel, leave the other two untouched data[currPixel + 0] = b; data[currPixel + 1] = (byte)Math.Min(g + 80, 255); data[currPixel + 2] = r; } } } }
保存処理はFileStorageクラスからこれまたストリームを取得して、BitmapEncoderクラスを用いて書きこみという流れです。
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption.GenerateUniqueName); using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, outputStream); // Grab the data from the SoftwareBitmap encoder.SetSoftwareBitmap(bitmap); await encoder.FlushAsync(); }
新しいAPIが色々出てきましたが、やっていることがわかりやすいコードではありますね。
Please give us your valuable comment