1. Code
  2. Mobile Development
  3. Android Development

Расширенная SDK для Android SDK: настройка камеры и датчика

Scroll to top

Russian (Pусский) translation by Dima (you can also view the original English article)

Сегодня расширенная реальность (AR) является горячей темой в мобильных приложениях. Смартфоны и планшеты имеют мощь и аппаратное обеспечение, которое позволяет разработчикам создавать интересные интересные приложения, которые интересны для использования живых камер и видеопотоков, гиперточных данных датчиков и других пользовательских данных в реальном времени. Сегодня мы начнем изучать мир дополненной реальности и то, что платформа Android может предложить разработчикам, которые хотят создавать AR-приложения и предоставлять своим пользователям глубокий и богатый опыт.


Также доступны в этой серии:

  1. Расширенная SDK для Android SDK: настройка камеры и датчика
  2. Android SDK Augmented Reality: Местоположение и расстояние

Шаг 0: предварительные условия и начало работы

Этот урок движется довольно быстро. Таким образом, мы ожидаем, что читатели будут знать все основы создания и запуска проектов Android. Мы также ожидаем, что у читателей появится Android-устройство, достаточно мощное для запуска приложений AR (таких как Nexus S). Большинство тестов этого приложения необходимо будет сделать на реальном устройстве Android, так как приложение в значительной степени зависит от камеры, датчиков и данных местоположения, которые недоступны в эмуляторе.

Мы предоставили пример приложения в сочетании с этим учебным пособием для загрузки. Этот проект будет усилен в ходе серии премиальных AR-обучающих программ, поэтому загрузите проект Android и следуйте за ним!


Часть 1: Какое AR-приложение мы разрабатываем?


Во-первых, нам нужно определить (в широком смысле), что будет делать это приложение. Мы хотим придерживаться типичных особенностей приложения AR и улучшать его с течением времени.

Итак, какое приложение мы будем строить? Мы собираемся создать AR-приложение на основе местоположения. Эти типы приложений AR обычно показывают, где вещи находятся в реальном мире, указывая, где приложение считает, что они находятся над просмотром камеры, когда пользователь держит телефон и перемещает его.

Другим типом приложения AR является тип, который распознает объект, используя алгоритмы компьютерного зрения, и может либо нарисовать информацию по камере, чтобы показать, что такое объект, как он ориентирован, либо, возможно, добавить или показать другие объекты в представлении. Хотя мы не будем создавать такое AR-приложение, многие из методов, которые мы преподаем здесь, могут применяться к любому типу приложения AR.

Основная архитектура приложения на основе местоположения включает в себя представление камеры, местоположение пользователя, ориентацию телефона по сравнению с реальным миром и список мест для элементов, которые мы хотим показать на дисплее, - данные, с которыми мы увеличиваем видение камеры мира.



Эта первая часть нашей серии расскажет о камере и датчиках. В следующей части мы поговорим о данных о местоположении и математике, участвующих в создании приложения.


Требования к приложениям: какие функции устройства Требуется ли наше приложение?

Для вашего типичного приложения AR требуется доступ к следующим функциям устройства:

  • Доступ к просмотру камеры
  • Доступ к местоположению пользователя
  • Доступ к другим датчикам устройства, особенно компас (акселерометр и гироскоп также могут быть полезны)

Приложению также могут потребоваться другие службы и разрешения, такие как доступ к сети, но они не являются центральными для AR-аспектов приложения.


Примечание по целевым устройствам: Nexus S


Не все устройства Android (или мобильные устройства в целом) имеют аппаратные спецификации для обработки требований AR-приложений. Для целей данного руководства мы ориентируемся на Nexus S, работающий под управлением Android 2.3.4, который удовлетворяет нашим специфическим требованиям к оборудованию. Поэтому наше приложение будет нацелено на очень специфическую версию Android SDK. Это упростит приложение. Однако требования SDK могут быть более гибкими, если манифест Android правильно идентифицирует любые требуемые аппаратные функции или вы реализуете альтернативные функции для менее мощных устройств.

Хотя Nexus S более чем способен выполнять разумные задачи AR, многие другие устройства также способны, включая некоторые более старые устройства. Если вы создаете производственное приложение, использующее технологию AR, вы должны тщательно протестировать на своих целевых устройствах ответ, удобство и правильную функциональность.


Часть 2: Настройка проекта


Теперь мы готовы начать разработку! Сначала создадим проект AR. Это приложение настроено так же, как и любой другой проект приложения в Eclipse.


Шаг 1: Создайте новый проект Eclipse


Начните с создания нового проекта Android в Eclipse. Вот подробности проекта, которые мы использовали для образца проекта (доступны для загрузки):

  • Название проекта: ARTUT
  • Уровень API мин/цель: 10
  • Запуск действия класса: ArtutActivity

Шаг 2: Настройка файла манифеста


Затем вы хотите настроить файл манифеста Android. Вы должны указать следующие настройки:

На вкладке Манифест добавьте настройки для следующего:

  • android.hardware.camera (обязательно = true)
  • android.hardware.camera.autofocus (обязательно = false)
  • android.hardware.location.gps (обязательно = true)
  • android.hardware.sensor.compass (Required = true)
  • android.hardware.sensor.gyroscope (обязательно = true)
  • android.hardware.sensor.accelerometer (Required = true)

На вкладке Приложение:

  • Отладка должна быть установлена ​​в true

На вкладке разрешения добавить настройки для:

  • android.permission.CAMERA
  • android.permission.FINE_LOCATION

Шаг 3: Подключите целевое устройство


Наконец, если вы еще этого не сделали, вам нужно настроить Android-устройство для тестирования и подключить его к компьютеру разработки через USB. Если вы этого еще не сделали, вам может потребоваться загрузить и установить драйверы перед использованием.

Нет смысла создавать виртуальное устройство Android (AVD) для использования с этим проектом, так как эмулятор не имеет достаточных возможностей для тестирования приложений с живыми камерами или сенсорами с любой степенью эффективности. Мы сделаем все наши разработки и тестирование против реального оборудования. Помимо обеспечения лучшей тестовой среды при использовании датчиков, камеры и другого оборудования, мы также обнаруживаем, что тестирование на реальном оборудовании происходит намного быстрее из-за ограничений производительности и возможностей эмулятора.


Часть 2: Работа с камерой


Наш первый реальный шаг в разработке AR-приложения включает в себя получение содержимого камеры, отображаемого на экране. Мы делаем это, реализуя пользовательский SurfaceView, который отображается в макете действия.


Шаг 1: Определение макета экрана App


Во-первых, нам нужно определить ресурс макета, который будет использоваться для основного экрана AR. FrameLayout наиболее подходит для нашего экрана, так как позволяет расслоение видов в области отображения. Поэтому наш ресурс компоновки, /res/layout/main.xml, может быть довольно простым:

1
 
2
<?xml version="1.0" encoding="utf-8"?> 
3
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android" 
4
    android:id="@+id/ar_view_pane"   
5
    android:layout_width="fill_parent" 
6
    android:layout_height="fill_parent"> 
7
</FrameLayout>

Шаг 2: Определение пользовательского SurfaceView для хранения содержимого камеры.


Затем вам нужно определить пользовательский элемент управления представлением для использования в вашем FrameLayout. Для этой цели можно использовать класс SurfaceView. Поэтому вы можете использовать этот класс для инкапсуляции рисунка вашей камеры.

1
 
2
public class ArDisplayView extends SurfaceView  
3
{ 
4
    public static final String DEBUG_TAG = "ArDisplayView Log"; 
5
    Camera mCamera; 
6
    SurfaceHolder mHolder; 
7
    Activity mActivity; 
8
     
9
    public ArDisplayView(Context context, Activity activity) {  
10
        super(context); 
11
 
12
        mActivity = activity; 
13
        mHolder = getHolder(); 
14
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
15
        mHolder.addCallback(this);  
16
 
17
    }

ArDisplayView класса начинается с конструктором. Мы добавили Activity как параметр конфигурации (подробнее об этом на следующем шаге). Конструктор должен инициализировать основной SurfaceHolder, который управляет рисунком на экране.

(Обратите внимание, что хотя метод setType () устарел, и в документации Android SDK говорится, что он больше не нужен, мы обнаружили, что код камеры не будет функционировать без него, он просто не запускается, даже на самом новом устройства.)

Мы добавили соответствующие переменные-члены для работы с камерой, и мы также поддерживаем активность, чтобы мы могли реагировать на изменения ориентации и любой другой удобный доступ к Контексту или Деятельности, которые могут нам понадобиться.


Шаг 3: Реализация обратных вызовов SurfaceHolder


Затем вам нужно будет реализовать обратные вызовы SurfaceHolder внутри класса. Обновите класс ArDisplayView, чтобы он реализовал интерфейс SurfaceHolder.Callback, например:

1
 
2
public class ArDisplayView extends SurfaceView implements SurfaceHolder.Callback 
3
{ 
4
    //… 

5
}

Это потребует переопределения и реализации трех новых методов: surfaceCreated (), surfaceChanged () и surfaceDestroyed ().

При работе с камерой предусмотрен ряд шагов, необходимых для запуска и выключения. Эти шаги четко описаны в документах Android SDK для класса Camera. Мы в основном отбрасываем эти шаги в соответствующие обратные вызовы SurfaceHolder.


Шаг 4: Реализация обратного вызова surfaceCreated ()


Начнем с метода обратного вызова surfaceCreated(). Здесь мы запрашиваем камеру, устанавливаем ориентацию дисплея камеры на основе текущей ориентации устройства (чтобы предварительный просмотр камеры всегда отображался справа вверх) и вызывал метод setPreviewDisplay (), чтобы связать предварительный просмотр камеры с нашим SurfaceHolder.

1
 
2
public void surfaceCreated(SurfaceHolder holder) {         
3
   mCamera = Camera.open(); 
4
         
5
   CameraInfo info = new CameraInfo();      
6
   Camera.getCameraInfo(CameraInfo.CAMERA_FACING_BACK, info);           
7
   int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();   
8
   int degrees = 0;     
9
   switch (rotation) {       
10
      case Surface.ROTATION_0: degrees = 0; break;          
11
      case Surface.ROTATION_90: degrees = 90; break;        
12
      case Surface.ROTATION_180: degrees = 180; break;         
13
      case Surface.ROTATION_270: degrees = 270; break;     
14
   }      
15
   cam.setDisplayOrientation((info.orientation - degrees + 360) % 360); 
16
         
17
   try { 
18
       mCamera.setPreviewDisplay(mHolder); 
19
   } catch (IOException e) { 
20
      Log.e(DEBUG_TAG, "surfaceCreated exception: ", e);     
21
   }   
22
}

Шаг 5: Внедрение обратного вызова surfaceChanged()


Большая часть интересного кода для предварительного просмотра камеры происходит в обратном вызове surfaceChanged (). Здесь мы запрашиваем параметры камеры и проверяем, какие поддерживаемые размеры предварительного просмотра. Нам нужно найти размер предварительного просмотра, который может быть размещен на поверхности, поэтому мы ищем ближайшее совпадение и используем его как наш размер предварительного просмотра. Затем мы устанавливаем формат предварительного просмотра камеры, фиксируем изменения параметров камеры и, наконец, вызываем метод startPreview (), чтобы начать отображение предварительного просмотра камеры на нашей поверхности.

1
 
2
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)  
3
{         
4
   Camera.Parameters params = mCamera.getParameters();      
5
   List<Size> prevSizes = params.getSupportedPreviewSizes(); 
6
   for (Size s : prevSizes) 
7
   { 
8
      if((s.height <= height) && (s.width <= width)) 
9
      { 
10
         params.setPreviewSize(s.width, s.height); 
11
         break; 
12
      }  
13
   } 
14
            
15
   mCamera.setParameters(params); 
16
   mCamera.startPreview(); 
17
}

Шаг 6: Внедрение обратного вызова surfaceDestroyed ()


Мы заканчиваем методом обратного вызова surfaceDestroyed(). Здесь мы закрываем предварительный просмотр камеры и освобождаем ресурсы камеры.

1
 
2
public void surfaceDestroyed(SurfaceHolder holder) {     
3
   cam.stopPreview(); 
4
   cam.release();   
5
}

Шаг 7: Пользовательский просмотр камеры и основная активность

Теперь вам нужно добавить свои пользовательские представления в элемент управления FrameLayout. Для этого обновите метод onCreate() класса ArtutActivity, например:

1
 
2
public void onCreate(Bundle savedInstanceState) { 
3
   super.onCreate(savedInstanceState); 
4
   setContentView(R.layout.main); 
5
         
6
   FrameLayout arViewPane = (FrameLayout) findViewById(R.id.ar_view_pane); 
7
         
8
   ArDisplayView arDisplay = new ArDisplayView(this); 
9
   arViewPane.addView(arDisplay); 
10
}

Это добавляет класс просмотра предварительного просмотра камеры, называемый ArDisplayView в FrameLayout. Если вы запустите приложение сейчас, действие запустится, и вы увидите предварительный просмотр камеры на экране.

Заметка о цифрах: Захват экрана DDMS по умолчанию не фиксирует предварительный просмотр камеры. Запустите приложение самостоятельно, чтобы увидеть настоящую функциональность.


Часть 3: Работа с датчиками устройства


Наш следующий шаг в разработке приложения AR включает в себя доступ к данным датчика устройства. Нам также нужен способ наложения содержимого поверх предварительного просмотра камеры. Мы делаем это, реализуя настраиваемое представление, которое можно сложить поверх ArDisplayView, отображаемого в данный момент в элементе управления FrameLayout.


Шаг 1: Отображение содержимого Overlay


Во-первых, вам нужно определить настраиваемый элемент управления представлением для наложения содержимого наложения. Создайте новый класс OverlayView, который является производным от класса View. Этот класс начинается просто для этой части учебника. Мы просто хотим наложить некоторые данные датчиков сверху камеры (пока еще нет фантазии). Для этого мы создаем переменные-члены для хранения последних известных данных датчика для каждого интересующего нас датчика. Затем мы реализуем метод onDraw () нашего представления и наносим некоторый текст на холст.

1
 
2
 
3
public class OverlayView extends View { 
4
 
5
    public static final String DEBUG_TAG = "OverlayView Log"; 
6
    String accelData = "Accelerometer Data"; 
7
    String compassData = "Compass Data"; 
8
    String gyroData = "Gyro Data"; 
9
     
10
    public OverlayView(Context context) { 
11
        super(context);     
12
    } 
13
     
14
    @Override 
15
    protected void onDraw(Canvas canvas) { 
16
        super.onDraw(canvas); 
17
            
18
        Paint contentPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
19
        contentPaint.setTextAlign(Align.CENTER); 
20
        contentPaint.setTextSize(20); 
21
        contentPaint.setColor(Color.RED); 
22
        canvas.drawText(accelData, canvas.getWidth()/2, canvas.getHeight()/4, contentPaint); 
23
        canvas.drawText(compassData, canvas.getWidth()/2, canvas.getHeight()/2, contentPaint); 
24
        canvas.drawText(gyroData, canvas.getWidth()/2, (canvas.getHeight()*3)/4, contentPaint); 
25
    } 
26
}

Метод onDraw() выполняет всю работу здесь. Мы настраиваем Paint с соответствующими текстовыми атрибутами, а затем рисуем текст на холсте с помощью метода drawText().

Зачем использовать пользовательский вид вместо обычных элементов управления? В дальнейшем нам понадобится точность для размещения объектов AR в пределах камеры, которые являются репрезентативными для местоположений мест реального мира. Альтернативой этому методу является использование 3D-рендеринга для лучшего получения дескриптора глубины и расстояния. В AR-приложении местоположения это обычно менее важно, поскольку расстояния часто довольно обширны (километров, а не метров).


Шаг 2: Реализация обратных вызовов SurfaceHolder


Затем вам необходимо реализовать интерфейс SensorEventListener в классе. Обновите класс OverlayView, чтобы он реализовал интерфейс SensorEventListener, например:

1
 
2
public class OverlayView extends View implements SensorEventListener {

Это потребует переопределения и реализации двух новых методов: onAccuracyChanged() и onSensorChanged(). Для целей этого урока нас действительно интересует только метод onSensorChanged().


Шаг 3: Регистрация для обновлений данных датчиков


Прежде чем внедрять обратные вызовы SensorEventListener, мы хотим зарегистрироваться для соответствующих обновлений данных датчиков. Для этого обновите метод onCreate () класса OverlayView.

Начните с запроса SensorManager и получения датчиков, которые вы хотите просмотреть. В этом случае мы будем смотреть акселерометр, компас и гироскоп. Затем зарегистрируйтесь для прослушивания событий на каждом из этих датчиков.

1
 
2
        SensorManager sensors = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); 
3
        Sensor accelSensor = sensors.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
4
        Sensor compassSensor = sensors.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); 
5
        Sensor gyroSensor = sensors.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 
6
 
7
        boolean isAccelAvailable = sensors.registerListener(this, accelSensor, SensorManager.SENSOR_DELAY_NORMAL); 
8
        boolean isCompassAvailable = sensors.registerListener(this, compassSensor, SensorManager.SENSOR_DELAY_NORMAL);       
9
        boolean isGyroAvailable = sensors.registerListener(this, gyroSensor, SensorManager.SENSOR_DELAY_NORMAL);

Теперь вы готовы реализовать обратный вызов датчика onSensorChanged (), чтобы реагировать на эти обновления датчиков.


Шаг 4: Внедрение обратного вызова onSensorChanged()


Большая часть интересного кода для обновлений датчиков происходит в обратном вызове onSensorChanged(). Здесь нам нужно, чтобы представление реагировало на изменения датчика. Мы зарегистрировались для нескольких различных типов изменений, поэтому этот метод можно вызвать для любого изменения сенсора. На данный момент мы просто хотим сэкономить данные датчика, которые изменились, а затем заставить просмотр обновить его содержимое. Мы можем сделать это, просто аннулируем представление и заставляя его перерисовывать.

1
 
2
public void onSensorChanged(SensorEvent event) {         
3
   StringBuilder msg = new StringBuilder(event.sensor.getName()).append(" "); 
4
   for(float value: event.values) 
5
   { 
6
      msg.append("[").append(value).append("]"); 
7
   } 
8
         
9
   switch(event.sensor.getType()) 
10
   { 
11
      case Sensor.TYPE_ACCELEROMETER: 
12
         accelData = msg.toString(); 
13
         break; 
14
      case Sensor.TYPE_GYROSCOPE: 
15
         gyroData = msg.toString(); 
16
         break; 
17
      case Sensor.TYPE_MAGNETIC_FIELD: 
18
         compassData = msg.toString(); 
19
         break;               
20
   } 
21
         
22
   this.invalidate();     
23
}

Шаг 5: Пользовательский накладной и основная деятельность


Теперь вам нужно добавить свой пользовательский вид в элемент управления FrameLayout. Для этого обновите метод onCreate() класса ArtutActivity. Добавьте следующий код чуть ниже вызова addView (), который добавляет ArDisplayView:

1
 
2
OverlayView arContent = new OverlayView(getApplicationContext()); 
3
arViewPane.addView(arContent);

Это складывает два вида: сначала класс просмотра предварительного просмотра камеры, называемый ArDisplayView, а затем накладывает OverlayView, который отображает данные датчика поверх него. Если вы запустите приложение сейчас, действие запустится, и вы увидите предварительный просмотр камеры на экране с данными датчиков, отображаемыми поверх него (помните, что вы не можете делать снимки экрана камеры, поэтому на следующем рисунке показано только содержимое наложения) ,



Если вы используете приложение в данный момент, вы, вероятно, заметили, что данные датчиков обновляются очень быстро, несмотря на то, что они требуют достаточно медленной скорости, чтобы работать с изменениями ориентации. Эти датчики устройства имеют очень высокую степень чувствительности. В конечном итоге это приведет к шаткости в пользовательском интерфейсе. В конце концов, нам нужно будет реализовать некоторые алгоритмы сглаживания, чтобы удержать дрожи, когда мы начнем использовать данные датчиков в нашем приложении.

Вам также может быть интересно, будем ли мы использовать все эти датчики и какие их устройства. Мы не обязательно будем использовать все датчики, но мы подумали, что мы покажем вам, как они выглядят, и как получить к ним доступ, если ваши конкретные интересы AR лежат на разных датчиках.

  • Числа акселерометра находятся в единицах СИ (м/с^2, т. е. В метрах в секунду, где гравитация Земли составляет 9,81 м/с^2).
  • Магнитные датчики находятся в микро-Тесласе. Когда они входят в формы x, y и z, мы можем измерить вектор и сравнить с гравитацией, чтобы определить, где (магнитный) север по отношению к устройству.
  • Гироскоп измеряет вращение вокруг каждой оси в радианах в секунду. Это также можно использовать для расчета относительной ориентации устройства.

Заключение

Это завершает первую часть нашего учебника AR. Расширенная реальность - захватывающий жанр для приложений на платформе Android. Android SDK предоставляет все необходимое для разработки гладких и интересных AR-приложений, но не все устройства могут удовлетворить требованиям к оборудованию, требуемым этими приложениями. К счастью, новейшее поколение Android-устройств является самым мощным, но многие из Android-устройств прекрасно способны работать с расширенными AR-приложениями.

В следующей части этой серии мы перейдем к сбору данных о местоположении и размещению объектов AR на экране в определенном месте. Это будет включать в себя различные математические алгоритмы, но конечным результатом будет ... увеличение!