Блог Сергея Байдачного

Мой блог о технологиях

Интеграция с камерой

leave a comment »

 

В первой версии Windows Phone (7) разработчик имел очень ограниченный доступ к камере. Фактически вся работа сводилась к вызову стандартного приложения по работе с камерой с помощью класса CameraCaptureTask. Объекты этого класса обладают методом Show, способным инициировать стандартное приложение по работе с камерой (и деактивировать Ваше), а с помощью обработчика события Completed можно было получить отснятое изображение. Подобный подход хорош, если Вам не нужна тесная интеграция с камерой и не хочется делать дополнительную работу.

А вот в Windows Phone 7.5 разработчик получил значительно больше возможностей. При этом слово «больше» явно преуменьшает тот набор функциональности, который можно использовать сегодня. По большому счету Вы можете без труда написать собственное приложение по работе с камерой, позволяя пользователю устанавливать различные настройки. При этом речь идет как о создании фотографий, так и о полном доступе к данным, поступающим на камеру. Давайте рассмотрим новые механизмы более детально.

Начнем с того, что для использования камеры в своем приложении необходимо обязательно задекларировать такую возможность. Это делается с помощью Capability элемента с именем ID_CAP_ISV_CAMERA, который прописывается в манифесте приложения (WMAppManifest.xml). При этом данная декларация позволяет использовать как стандартную, так и фронтальную (лицевую) камеру (по выбору пользователя через интерфейс приложения). Декларация прописана по умолчанию в шаблоне проекта Visual Studio, поэтому Вам вряд ли нужно будет выполнять этот шаг. Но если Вы решили использовать именно фронтальную камеру, так как именно с помощью нее можно выполнить некоторые функции Вашего приложения, то необходимо задекларировать еще одну возможность, с именем ID_HW_FRONTCAMERA. При этом нужно помнить, что не все телефоны оснащены лицевой камерой. Последняя возможность не декларируется по умолчанию, поэтому ее потребуется прописать явно.

Теперь необходимо определиться, какое приложение Вы хотите реализовать. Дело в том, что в Windows Phone 7.5 появилось сразу два API по работе с камерой. Первое API является частью платформы Windows Phone и позволяет реализовать приложение по съемке фотографий. Второе API является частью SilverLight 4 и позволяет обрабатывать весь аудио и видео поток, поступающий на камеру. Преимущество первого API – возможность обрабатывать события, связанные с фокусом, вспышкой и другими элементами телефона. Преимущество Silverlight API – его универсальность. В любом случае оба API можно комбинировать.

Начнем наш обзор с Windows Phone API. Тут выделяют три основных класса: PhotoCamera, PictureDecoder, Extentions. Основную работу выполняет первый класс. А вот два других являются вспомогательными и позволяют преобразовать объект типа WriteableBitmap в JPEG и наоборот. Фактически второй и третий классы реализуют мостик между Silverlight и объектом типа PhotoCamera. При этом, Silverlight 4 не поддерживал стандартных механизмов преобразования BMP изображений в JPEG, что затрудняло работу разработчиков при создании веб-приложений. Но телефон ведь не только позволяет снимать изображение с камеры, но и преобразовывать его в JPEG. Именно поэтому такая возможность стала доступна и разработчику, как открытый API уже существующих в устройстве возможностей.

Не буду детально останавливаться на PictureDecoder и Extensions, а лишь отмечу, что первый класс обладает двумя статическими методами, позволяющими получить готовый WriteableBitmap, получив в качестве параметров ссылку на поток с файлом JPEG. А вот второй класс является расширителем класса WriteableBitmap и позволяет добавить в интерфейс последнего два метода (LoadJpeg и SaveJpeg). Иными словами Вы можете использовать эти методы, как методы экземпляров типа WriteableBitmap.

Теперь перейдем к основному классу – PhotoCamera. Тут есть два небольших правила-рекомендации. Объект типа PhotoCamera правильно создавать и инициализировать внутри перегруженного метода OnNavigatedTo. Уничтожать данный объект следует внутри метода OnNavigatingFrom. Это позволит гарантировать, что все ресурсы будут освобождены своевременно, если приложение поддерживает навигацию на другие страницы. Создание самого объекта типа PhotoCamera не вызывает затруднений – тут присутствует конструктор без параметров, а также конструктор, который принимает тип камеры (обычная или фронтальная).

Я не смог найти ни одного устройства с фронтальной камерой в своих запасниках, поэтому не смог проверить, можно ли получать изображение с обеих камер одновременно. Но если можно, то это позволит создать много интересных приложений. Фронтальную камеру сегодня поддерживает HTC Titan, HTC Radar и Samsung I8350. Если у Вас одно из этих устройств, попробуйте проверить и написать.

Итак, создав объект типа PhotoCamera, следует определить необходимые в приложении события, ассоциированные с этим объектом и задать свойства. Я не буду перечислять основные свойства и события, а просто приведу небольшой пример.

В шаблонный xaml, внутрь элемента Grid с именем ContentPanel, добавим код:

 

   1:   <StackPanel>
   2:       <Rectangle Height="400" Width="400" Margin="12,17,0,0" Name="videoRect" />
   3:   </StackPanel>

 

В файл с кодом добавим следующий текст:

 

   1:  PhotoCamera camera;
   2:  MediaLibrary library;
   3:   
   4:  protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
   5:  {
   6:      if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
   7:      {
   8:          camera = new PhotoCamera(CameraType.Primary);
   9:   
  10:          videoRect.Fill = new VideoBrush();
  11:          ((VideoBrush)videoRect.Fill).SetSource(camera);
  12:          library = new MediaLibrary();
  13:   
  14:          CameraButtons.ShutterKeyHalfPressed += 
  15:  new EventHandler(CameraButtons_ShutterKeyHalfPressed);
  16:          CameraButtons.ShutterKeyPressed += 
  17:  new EventHandler(CameraButtons_ShutterKeyPressed);
  18:          camera.CaptureImageAvailable += 
  19:  new EventHandler<ContentReadyEventArgs>(camera_CaptureImageAvailable);
  20:      }
  21:  }
  22:   
  23:  void camera_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
  24:  {
  25:      string fileName = Guid.NewGuid().ToString() + ".jpg";
  26:      library.SavePictureToCameraRoll(fileName, e.ImageStream);
  27:      Deployment.Current.Dispatcher.BeginInvoke(delegate()
  28:      {
  29:          MessageBox.Show("Image saved");
  30:      });
  31:  }
  32:   
  33:  void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)
  34:  {
  35:      camera.CaptureImage();
  36:  }
  37:   
  38:  void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)
  39:  {
  40:      camera.Focus();
  41:  }
  42:   
  43:  protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
  44:  {
  45:      if (camera != null)
  46:      {
  47:          camera.Dispose();
  48:          camera.CaptureImageAvailable -= camera_CaptureImageAvailable;
  49:      }
  50:  }

 

Если развернуть созданное приложение на устройстве, то мы получим приложение, которое отображает данные с камеры и позволяет сделать и сохранить фотографию в библиотеку изображений:

 

image

 

На картинке я специально повернул телефон так, как он расположен во время съемки. Как видно, чтобы изображение на экране, соответствовало изображению с камеры, нужно элемент, куда мы выводим изображение, повернуть на 90 градусов.

Итак, что мы увидели в данном примере:

1). Изображение можно снимать, используя стандартную клавишу камеры в телефоне. Для этого используется класс CameraButtons, содержащий несколько статических событий, позволяющих нам подключить наш код. Тут и возможность провести фокус (относительно центра или какой-то точки), тут и возможность обработать поток, который связан со сформированным изображением, доступным после завершения съемки.

2). Для работы с камерой есть ряд простых методов, такие как Focus или CaptureImage. Эти методы инициируют некоторый процесс в параллельном потоке, и передают свои результаты в параметрах таких событий как CaptureImageAvailable или AutoFocusCompleted. Поэтому, если Вы хотите изъять фотографию, то нужно определить обработчик первого события. Но изменение интерфейса нужно выполнять, передав управление в интерфейсный поток.

3). PhotoCamera позволяет сохранить изображение в виде потокового объекта, который уже преобразован к формату JPEG. Поэтому, если Вы хотите предварительно обработать изображение, то поток можно преобразовать во WritableBitmap с помощью классов, упоминавшийся выше, обработать и снова преобразовать в JPEG.

Сценарий выше работает если Вы хотите снять обычное изображение с камеры. Но если приложение немного более сложное, например, накладывает дополнительные элементы (например, усы на лица людей в кадре), то необходимо привлечь несколько дополнительных методов объекта типа PhotoCamera. Одним из таких методов является GetPreviewBufferArgb32, позволяющий вернуть текущий фрейм для дальнейших манипуляций. Получив массив данных, разработчик может выполнить их предварительную обработку, преобразовать во WritableBitmap и выдать на экран. В этом случае VideoBrush не используется совсем, а используется объект Image, в который и выводиться очередной WriteableBitmap. Естественно, что обработка каждого следующего фрейма проводиться в методе, который запускают в параллельном потоке. А частота выдачи изображений на экран, зависит от сложности алгоритма, обрабатывающего изображение.

Если говорить про Silverlight 4 API, то тут ничего не поменялось. Работа начинается с классов AudioCaptureDevice, VideoCaptureDevice и CaptureDeviceConfiguration. Эти классы используются для получения ссылок на доступные аудио и видео устройства. Если устройств несколько, то Вы можете предоставить пользователю выбор, с каким устройством работать.

Основным классом является CaptureSource, который позволяет начать запись. Внутри этого класса описаны ссылки на аудио и видео устройства, а также присутствуют такие методы как Start и Stop, позволяющие запустить или остановить работу камеры. Кроме того, объект данного класса может служить источником данных для VideoBrush.

Отличие классов Silverlight API состоит в том, что с помощью них можно выполнять запись изображения в видео-файл (MP4). Для этого используется класс FileSink, который имеет свойства CaptureSource и IsolatedStorageFileName – все, что необходимо для начала записи. При установке свойства CaptureSource соответствующий объект должен быть остановлен. Если Вы хотите написать собственный декодер, то можно использовать такие классы как VideoSink и AudioSink. Последние можно использовать и для передачи аудио и видео в различных системах видео чата.

Реклама

Written by Sergiy Baydachnyy

01.01.2012 в 22:41

Опубликовано в Windows Phone

Tagged with

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: