В этой статье я научу вас, как разработать приложение для смартфонов Nokia Lumia 1020 с 41-мегапиксельной (Мп) камерой и Nokia Lumia 1520 с 20-мегапиксельной (Мп) камерой. Я сосредоточусь в основном на Nokia Lumia 1020, но эта информация применима ко всем устройствам Lumia Windows Phone 8 с технологией PureView. Сначала я рассмотрю PureView — технологию, используемую в мощных камерах этих смартфонов, а затем поясню доступные вам продвинутые средства, позволяющие улучшать ваши фотоснимки. Я дам обзор Nokia Imaging SDK (в нем масса готовых графических фильтров) и расскажу, как его использовать. Кроме того, мы обсудим типичный рабочий процесс, необходимый для создания приложения камеры, и покажу, как создать светофильтр «сдвиг и уклон» (tilt-shift photo filter) для имитации малой глубины резкости (shallow depth of field). Итак, начнем.
Что представляет собой технология PureView в смартфоне с 41-мегапиксельной камерой
Технология PureView состоит из аппаратного обеспечения и связанного программного обеспечения. Совместно они позволяют захватывать и сохранять высококачественные изображения с высоким разрешением. Три основных аспекта технологии PureView: высокоразрешающая матрица камеры, избыточная дискретизация (oversampling) и приближение без потерь (lossless zoom). Кратко поясню каждый из этих аспектов.
Центральное место в технологии PureView занимает высокоразрешающая матрица, имеющая 7728 пикселей по ширине и 5368 пикселей по высоте, что дает более 41 Мп. Это позволяет камере захватывать большие фотоснимки, в шесть раз большие, чем обычные фотографии с 5 Мп.
На рис. 1 сравниваются картинки с разрешением 41 Мп и 5 Мп. Благодаря разрешению в 41 Мп вы можете делать высококачественные снимки с разрешением 34 Мп в формате 16:9 (7728 × 4354), а также с разрешением 38 Мп в формате 4:3 (7152 × 5368), как показано в проекции матрицы камеры на рис. 2.
Рис. 1. Сравнение картинок с разрешением 41 Мп и 5 Мп
7,728 | 7728 |
5,368 | 5368 |
3,072 | 3072 |
1,728 | 1728 |
41MP | 41 Мп |
5MP | 5 Мп |
Увеличить
Рис. 2. Приближение без потерь
5MP, 3x Lossless Zoom | 5 Мп, трехкратное приближение без потерь |
34MP 16:9 Resolution | 34 Мп, разрешение 16:9 |
38MP 4:3 Resolution | 38 Мп, разрешение 4:3 |
Избыточная дискретизация пикселей наблюдается, когда камера делает 41-мегапиксельный снимок и создает высококачественное изображение в 5 Мп. Это картинка, которая показывается на экране смартфона. Более того, процесс избыточной дискретизации сохраняет все богатство деталей в изображении, но отфильтровывает любые визуальные шумы.
Третий аспект технологии PureView — приближение без потерь; это просто означает, что при приближении изображения вы не теряете в его качестве. Это возможно потому, что в любой момент вам доступна исходная 41-мегапиксельная картинка, которая подвергается избыточной дискретизации для вывода фотоснимка 5 Мп. При использовании зума вы на самом деле приближаете часть исходного снимка 41 Мп. При приближении вплоть до трехкратного вы по-прежнему имеете дело с частями исходного снимка 41 Мп. И даже при максимальном зуме качестве вашей фотографии остается на уровне качества снимка 5 Мп. Благодаря избыточной дискретизации качество картинки становится только лучше при приближении. Как это происходит, уже было показано на рис. 2.
Nokia Imaging SDK
При создании приложения камеры снимок с высоким разрешением является исходным материалом, но вам понадобится продвинутый стек программного обеспечения, способного использовать огромные изображения и дать вам возможность операций над ними. Здесь и вступает в игру Nokia Imaging SDK (bit.ly/1hJkmpl). Он предоставляет набор продвинутой функциональности для доступа к снимкам, сделанным высокоразрешающей камерой.
Nokia Imaging SDK включает частичное декодирование JPEG, которое называют технологией Random Access JPEG (RAJPEG). RAJPEG обеспечивает произвольный доступ к JPEG-данным, быстрое уменьшение масштаба (downscaling) изображений и мгновенное частичное декодирование (instant partial decoding). Эти средства RAJPEG поддерживают манипуляцию изображением в реальном времени. В Nokia Imaging SDK содержится более 50 фильтров, эффектов и улучшений. В нем даже поддерживается набор наиболее распространенных операций над изображениями, таких как отсечение (crop), изменение размеров (resize), вращение (rotate), отмена (undo) и многие другие. Эти готовые средства помогают создавать продвинутые приложения камеры, а также программы для работы со снимками, не заботясь о самой распространенной функциональности. Чтобы использовать Nokia Imaging SDK в проекте, следуйте инструкциям на странице Nokia Lumia Developer Library (bit.ly/KzDPNG).
API в Imaging SDK
API, доступные в Imaging SDK, можно легко применять к захваченным камерой данным изображения, написав всего несколько строк кода:
var imageSource = new StreamImageSource(e.ChosenPhoto); // Определяем применяемые эффекты var filterEffect = new FilterEffect(imageSource); filterEffect.Filters = new [] { new FogFilter() }; // Рендеринг изображения с помощью WriteableBitmapRenderer WriteableBitmapRenderer renderer = new WriteableBitmapRenderer(filterEffect, myImageBitmap,OutputOption.PreserveAspectRatio); await renderer.RenderAsync();
Здесь e.ChosenPhoto используется, чтобы создать StreamImageSource; e.ChosenPhoto может поступать непосредственно со снимка, захваченного камерой, или из любого снимка в альбоме. Затем я создаю эффект на основе фильтров для применения к снимку и добавляю художественный FogFilter к массиву фильтров в своем эффекте. При необходимости этот массив может содержать множество фильтров, которые потом применяются и подвергаются рендерингу в myImageBitmap, используя WriteableBitmapRenderer. Как и предполагает его имя, он осуществляет рендеринг изображения-источника в WriteableBitmap. Наконец, метод RenderAsync помогает сделать рендеринг изображения асинхронной операцией.
Наряду с FogFilter вы можете применять к снимку более 50 других фильтров из Imaging SDK. На рис. 3 показан список корректирующих фильтров (enhancement filters) в бесплатном App Filter Explorer, доступном для разработчиков в готовом виде. Он включает такие фильтры, как AutoEnhanceFilter, AutoLevelsFilter, ColorBoostFilter и ExposureFilter. Это фильтры, которые можно напрямую применять к любому снимку или к изображению, захватываемому камерой в реальном режиме, для улучшения качества.
Рис. 3. Корректирующие фильтры в бесплатном App Filter Explorer
Существуют другие фильтры для изменения яркости (BrightnessFilter) и контраста (ContrastFilter), которые принимают соответствующие параметры. Есть ряд фильтров исключительно для художественных эффектов, например emboss (выдавливание выпуклого изображения), grayscale (полутоновое изображение) и сепия. Также имеются «фильтры» для редактирования изображений, которые обеспечивают ранее упомянутые часто используемые функции вроде вращения, переворачивания, отражения и др. Их можно применять к одному изображению несколько раз, один поверх другого, что позволяет создавать драматические эффекты.
Рабочий процесс приложения высокоразрешающей камеры
Теперь, когда я рассказал об аппаратных возможностях и средствах Imaging SDK, я покажу типичный рабочий процесс, необходимый для создания мощного приложения камеры. Поскольку я имею дело с огромным изображением, мне придется соблюдать осторожность, чтобы мое приложение не замедлило другие программы и не заняло чрезмерный объем памяти. Этого можно избежать, не пытаясь напрямую манипулировать огромным изображением в камере.
В любой момент времени в камере присутствуют два изображения с размерами 41 Мп и 5 Мп; последний показывается на панели обзора камеры (camera view panel). В своем приложении я буду всегда работать с 5-мегапиксельным снимком, который может быть избыточно дискретизированным изображением всего фотоснимка, приближенной частью картинки или избыточно дискретизированным и частично приближенным фрагментом.
Рабочий процесс этого приложения показан на рис. 4.
Увеличить
Рис. 4. Рабочий процесс приложения для работы с изображениями
Acquire Photo | Получение снимка |
Local Storage | Локальное хранилище |
Magic | Магия |
Save image | Сохранение изображения |
Camera capture | Захват камерой |
Photo chooser | Селектор фотоснимков |
Photo capture | Захват снимка |
Process image | Обработка изображения |
Apply filters | Применение фильтров |
Индивидуальные этапы включают:
- захват изображения с высоким разрешением;
- его сохранение в вашем локальном хранилище;
- магические пассы с использованием Imaging SDK;
- уменьшение масштаба конечного изображения до 5 Мп;
- сохранение улучшенного 5-мегапиксельного изображения в каталоге, куда помещаются снимки с камеры (camera roll).
Создание светофильтра: сдвиг и уклон
Теперь я пошагово пройду с вами по рабочему процессу в своем приложении камеры. Фотография с использованием сдвига и уклона — это применение движений камеры, особенно уклона, для избирательного фокусирования, чтобы сымитировать пейзаж как на миниатюре (рис. 5). Подробнее о фотографии по методу сдвига и уклона см. bit.ly/1bRYYNK. В этом приложении я моделирую малую глубину резкости с помощью цифровой постобработки, используя несколько фильтров в Nokia Imaging SDK.
Увеличить
Рис. 5. Эффект сдвига и уклона
Original | Оригинал |
After tilt shift | После сдвига и уклона |
Получение снимка Первый шаг в любом приложении камеры — получение изображения от камеры или галереи изображений. Это можно сделать тремя способами. Один из них — использование 5-мегапиксельной камеры по умолчанию с помощью CameraCaptureTask, который вызывает срабатывание обычного видоискателя камеры. Второй — использование «родного» элемента управления для выбора снимков, который называется PhotoChooserTask. Эти два варианта достаточны для большинства приложений камеры, но в продвинутом приложении, где нужно захватывать снимки с высоким разрешением, вы должны создать собственный видоискатель, который вызывает запуск встроенного приложения-видоискателя Pro Camera с высоким разрешением. Для этого применяется объект PhotoCaptureDevice. Список методов и свойств, поддерживаемых PhotoCaptureDevice см. на рис. 6.
Рис. 6. Методы и свойства, поддерживаемые PhotoCaptureDevice
UI Приложение для сдвига и уклона (tilt-shift app) содержит два объекта: OriginalImage (для отображения реального захваченного или выбранного изображения) и TiltShiftImage (для отображения конечного изображения после применения фильтра сдвига и уклона к оригиналу). SelectButton активизирует «родное» средство выбора снимков, а CameraButton — камеру, как показано в коде на рис. 7.
Рис. 7. XAML-код UI
<Canvas x:Name="LayoutRoot" Background="Transparent"> <TextBlock Text="" Style="{StaticResource PhoneTextNormalStyle}" /> <Image x:Name="TiltShiftImage" Height="480" Width="728" Stretch="UniformToFill" MouseLeftButtonUp ="TiltShiftImage_MouseLeftButtonUp"/> <Image x:Name="OriginalImage" Height="480" Width="728" Stretch="UniformToFill" Canvas.ZIndex="0" MouseLeftButtonUp="OriginalImage_MouseLeftButtonUp" Source="/Assets/Landscapes.jpg"/> <Rectangle x:Name="TiltshiftRegion" Fill="White" Height="65" Stroke="#FF0B7AFF" Canvas.Top="320" Width="728" Opacity="0.25" StrokeThickness="5"/> <Button x:Name="SelectButton" Content="Select" Click="PickAnImageButton_Click" Canvas.Left="4" Canvas.Top="398" /> <Button x:Name="CameraButton" Content="Camera" Click="CameraButton_Click" Canvas.Left="123" Canvas.Top="398" /> <Button x:Name="ProButton" Content="Pro Camera" Click="ProCameraButton_Click" Canvas.Left="254" Canvas.Top="398" /> <Button x:Name="SaveButton" Content="Save" Click="SaveImage_Click" Canvas.Left="630" Canvas.Top="398" /> <Button x:Name="TiltShiftButton" Content="Tilt Shift" Click="TiltShiftButton_Click" Canvas.Left="449" Canvas.Top="398" /> </Canvas>
Полученный UI камеры представлен на рис. 8.
Рис. 8. UI приложения для сдвига и уклона
Захват изображения с высоким разрешением Первые два способа (работа с обычной камерой и функциональностью селектора снимков) достаточно прямолинейны. Для этих целей в пространстве имен Microsoft.Phone.Tasks есть два объекта задач: CameraCaptureTask и PhotoChooserTask. Просто выберите изображение либо через селектор, либо как захваченные данные от камеры в качестве источника фильтра сдвига и уклона:
private void PickAnImageButton_Click(object sender, RoutedEventArgs e) { PhotoChooserTask chooser = new PhotoChooserTask(); chooser.Completed += PickImageCallback; chooser.Show(); } private void CameraButton_Click(object sender, RoutedEventArgs e) { CameraCaptureTask camera = new CameraCaptureTask(); camera.Show(); camera.Completed += PickImageCallback; }
Чтобы захватить снимок высокого разрешения, мне нужно создать собственный видоискатель, используя видеокисть (video brush), источником которой будет изображение от приложения Pro Camera:
<Canvas x:Name="Canvas" Tap="Canvas_Tap" Height="480" HorizontalAlignment="Center" VerticalAlignment="Center"> <Canvas.Background> <VideoBrush x:Name="ViewfinderVideoBrush" Stretch="Uniform"/> </Canvas.Background> <Border x:Name="FocusBracket" Width="80" Height="80" BorderBrush="White" BorderThickness="2" Margin="-40" Visibility="Collapsed" CornerRadius="360"/> <Image x:Name="FreezeImage" Visibility="Collapsed" Stretch="Uniform" Height="480"/> </Canvas>
Мне также требуется инициализировать приложение Pro Camera правильным разрешением в зависимости от устройства (Lumia 1020 или Lumia 1520) и нужным типом разрешения. Параметры перечислены в табл. 1.
Табл. 1. Параметры для снимка высокого разрешения
Модель | Настраиваемые вручную значения | Параметры для снимка высокого разрешения |
Lumia 1020 | RM-875, RM-876, RM-877 | 7712 x 4352 (16:9), 7136 x 5360 (4:3) |
Lumia 1520 | RM-937, RM-938, RM-940, RM-939 | 5376 x 3024 (16:9), 4992 x 3744 (4:3) |
На рис. 9 показано, как инициализировать приложение Pro Camera.
Рис. 9. Инициализация приложения Pro Camera
private void InitializeCamera() { Windows.Foundation.Size captureResolution; var deviceName = DeviceStatus.DeviceName; if (deviceName.Contains("RM-875") || deviceName.Contains("RM-876") || deviceName.Contains("RM-877")) { captureResolution = new Windows.Foundation.Size(7712, 4352); // 16:9 //captureResolution = new Windows.Foundation.Size(7136, 5360); // 4:3 } else if (deviceName.Contains("RM-937") || deviceName.Contains("RM-938") || deviceName.Contains("RM-939")) { captureResolution = new Windows.Foundation.Size(5376, 3024); // 16:9 //captureResolution = new Windows.Foundation.Size(4992, 3744); // 4:3 } else { captureResolution = PhotoCaptureDevice.GetAvailableCaptureResolutions( REAR_CAMERA_SENSOR_LOCATION).First(); } var task = PhotoCaptureDevice.OpenAsync(REAR_CAMERA_SENSOR_LOCATION, captureResolution).AsTask(); task.Wait(); _device = task.Result; _device.SetProperty( KnownCameraGeneralProperties.PlayShutterSoundOnCapture, true); if (_flashButton != null) { SetFlashState(_flashState); } AdaptToOrientation(); ViewfinderVideoBrush.SetSource(_device); if (PhotoCaptureDevice.IsFocusSupported(REAR_CAMERA_SENSOR_LOCATION)) { Microsoft.Devices.CameraButtons.ShutterKeyHalfPressed += CameraButtons_ShutterKeyHalfPressed; } Microsoft.Devices.CameraButtons.ShutterKeyPressed += CameraButtons_ShutterKeyPressed; }
Захват изображения от приложения Pro Camera включает события ShutterHalfKeyPressed и ShutterKeyPressed, как показано на рис. 10.
Рис. 10. Захват изображения через события нажатия кнопки затвора
private async void CameraButtons_ShutterKeyHalfPressed( object sender, EventArgs e) { if (!_focusing && !_capturing) { _focusing = true; await _device.FocusAsync(); _focusing = false; } } private async void CameraButtons_ShutterKeyPressed( object sender, EventArgs e) { if (!_focusing && !_capturing) { _capturing = true; var stream = new MemoryStream(); try { var sequence = _device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); } catch (Exception ex) { stream.Close(); } _capturing = false; if (stream.CanRead) { // Обработка изображения в потоке (stream). // Можно сохранить в локальном хранилище. } } }
Магические пассы Сначала я использую PickImageCallback для получения снимка, который потом задается как источник OriginalImage. Для доступа к размерам изображения применяется ImageProviderInfo.
Кроме того, я создаю фильтры и применяю их. Чтобы создать эффект сдвига и уклона, используются три фильтра: BlurFilter с KernelSize 15, ColorBoostFilter со значением 0.5 и вновь BlurFilter, но с KernelSize 21. Два фильтра размытия (blur filters) делают передний план и фон изображения слегка расфокусированными, а ColorBoostFilter осветляет область, которую я хочу использовать для создания эффекта миниатюры (miniature effect). Соответствующий код показан на рис. 11.
Рис. 11. Инициализация фильтров для эффекта
public partial class MainPage : PhoneApplicationPage { private Stream _img; private StreamImageSource imageSource; private ImageProviderInfo info; private FilterEffect _tiltshiftEffect = null; private WriteableBitmap _tiltshiftImageBitmap = null; // Конструктор public MainPage() { InitializeComponent(); _tiltshiftImageBitmap = new WriteableBitmap((int)TiltShiftImage.Width,(int)TiltShiftImage.Height); } ... private async void PickImageCallback(Object sender, PhotoResult e) { if (e.TaskResult != TaskResult.OK) { return; } _img = e.ChosenPhoto; imageSource = new StreamImageSource(_img); var bitmapImage = new BitmapImage(); bitmapImage.SetSource(e.ChosenPhoto); OriginalImage.Source = bitmapImage; info = await imageSource.GetInfoAsync(); TiltShift(); ...
Чтобы применить фильтр сдвига и уклона, мне нужны три прямоугольника: верхний — для размытия, средний — для осветления и нижний — тоже для размытия (рис. 12). В этом примере используется прямоугольная область TiltshiftRegion, которой пользователь может коснуться, а затем переместить в ту позицию, где должен произойти сдвиг и уклон. Осветленный прямоугольник, показанный на рис. 12, подвергается сдвигу и уклону, а остальная область размывается.
Рис. 12. Три прямоугольника, используемые для эффекта «сдвиг и уклон»
Blur top | Размытый верх |
Color boost | Осветление |
Blur bottom | Размытый низ |
Позиция TiltShiftRegion используется в вычислении трех прямоугольников, где применяются фильтры (рис. 13).
Рис. 13. Комбинирование фильтров для эффекта
private async void TiltShift() { if (info == null) return; try { var topLeft = new Windows.Foundation.Point(0, 0); var tiltShiftRegionTop = Canvas.GetTop(TiltshiftRegion); var delta = info.ImageSize.Height / TiltShiftImage.Height; tiltShiftRegionTop = (tiltShiftRegionTop + 10) * delta; var tiltShiftRegionBottom = (Canvas.GetTop(TiltshiftRegion) + 10) * delta + TiltshiftRegion.Height; var topRight = new Windows.Foundation.Point(info.ImageSize.Width, tiltShiftRegionTop); var bottomLeft = new Windows.Foundation.Point(0, tiltShiftRegionBottom); var bottomRight = new Windows.Foundation.Point( info.ImageSize.Width, info.ImageSize.Height); // Определяем применяемые эффекты _tiltshiftEffect = new FilterEffect(imageSource); List<IFilter> filters = new List<IFilter>(); filters.Add(new BlurFilter(15, ( new Windows.Foundation.Rect(topLeft, topRight)), BlurRegionShape.Rectangular)); filters.Add(new ColorBoostFilter(0.5)); filters.Add(new BlurFilter(23, (new Windows.Foundation.Rect(bottomLeft, bottomRight)), BlurRegionShape.Rectangular)); _tiltshiftEffect.Filters = filters; // Рендеринг изображения с помощью WriteableBitmapRenderer WriteableBitmapRenderer renderer = new WriteableBitmapRenderer(_tiltshiftEffect, _tiltshiftImageBitmap, OutputOption.PreserveAspectRatio); _tiltshiftImageBitmap = await renderer.RenderAsync(); TiltShiftImage.Source = _tiltshiftImageBitmap; } catch (Exception exception) { MessageBox.Show("Exception:" + exception.Message); return; } SaveButton.IsEnabled = true; }
Сохранение снимка Наконец, обработанное изображение нужно сохранить обратно в источнике (рис. 14).
Рис. 14. Сохранение обработанного изображения
private async void SaveImage_Click(object sender, RoutedEventArgs e) { SaveButton.IsEnabled = false; if (_tiltshiftEffect == null) { return; } var jpegRenderer = new JpegRenderer(_tiltshiftEffect); // JPEG-рендер предоставляет исходный буфер // для фильтрованного изображения IBuffer jpegOutput = await jpegRenderer.RenderAsync(); // Сохраняем изображение как JPEG в альбом MediaLibrary library = new MediaLibrary(); string fileName = string.Format("TiltShiftImage_{0:G}", DateTime.Now); var picture = library.SavePicture(fileName, jpegOutput.AsStream()); MessageBox.Show("Tilt Shift Image saved!"); SaveButton.IsEnabled = true; }
Ну вот и все. Теперь вы знаете, как использовать продвинутую технологию PureView для захвата изображения с камеры и выполнять постобработку картинки с помощью Nokia Imaging SDK.