В этой статье я научу вас, как разработать приложение для смартфонов 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.