Создание приложения камеры для смартфонов Nokia Lumia

OSzone.net » Microsoft » Разработка приложений » Windows Phone » Создание приложения камеры для смартфонов Nokia Lumia
Автор: Раджеш Лал
Иcточник: MSDN Magazine
Опубликована: 09.07.2014

В этой статье я научу вас, как разработать приложение для смартфонов 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,7287728
5,3685368
3,0723072
1,7281728
41MP41 Мп
5MP5 Мп

*
Увеличить

Рис. 2. Приближение без потерь

5MP, 3x Lossless Zoom5 Мп, трехкратное приближение без потерь
34MP 16:9 Resolution34 Мп, разрешение 16:9
38MP 4:3 Resolution38 Мп, разрешение 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Применение фильтров

Индивидуальные этапы включают:

Создание светофильтра: сдвиг и уклон

Теперь я пошагово пройду с вами по рабочему процессу в своем приложении камеры. Фотография с использованием сдвига и уклона — это применение движений камеры, особенно уклона, для избирательного фокусирования, чтобы сымитировать пейзаж как на миниатюре (рис. 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 1020RM-875, RM-876, RM-8777712 x 4352 (16:9), 7136 x 5360 (4:3)
Lumia 1520RM-937, RM-938, RM-940, RM-9395376 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.


Ссылка: http://www.oszone.net/24583/