Статьи

iOS SDK дополненной реальности: настройка камеры

Концепция дополненной реальности (AR) получила в последние годы большой интерес, поскольку iPhone и другие мобильные устройства предоставили в распоряжение миллионов людей по всему миру все более мощные процессоры, датчики и камеры. Впервые с тех пор, как этот термин был придуман в 1990-х годах, средний потребитель теперь может заглянуть в экран своего смартфона и найти слой реальности, о котором он даже не подозревал. Эта премиум-серия Mobiletuts + отправится в мир дополненной реальности и смешанной реальности. Он шаг за шагом продемонстрирует, как объединить камеру и датчики iPhone с компьютерной графикой, чтобы создать улучшенную, модифицированную или даже искаженную версию окружающего вас мира.

Основное внимание в этой серии руководств уделяется пониманию компонентов, доступных на iPhone, которые позволяют использовать дополненную реальность и смешанную реальность. Это будет достигнуто путем создания простой демонстрации AR, и это руководство поможет нам начать этот путь, решая основную задачу во многих приложениях AR: получение программного доступа к видеопотоку устройства.


Начните с запуска Xcode и создания нового проекта. Выберите «View-based Application» в качестве типа шаблона и нажмите «Next»:


На следующем экране введите «MobiletutsAR» в качестве названия продукта .

Для поля « Идентификатор компании» я использовал «com.mobiletuts.ardemo», но вам нужно будет предоставить уникальный идентификатор, который соответствует вашему собственному профилю обеспечения разработчика или специального распределения.

Процесс настройки устройства для тестирования приложений выходит за рамки данного руководства, но документация по этому процессу доступна из следующих источников:

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

Выберите «iPhone» в раскрывающемся списке « Семейство устройств» . Хотя данное руководство будет сосредоточено на создании простого приложения AR для iPhone, продемонстрированные принципы будут применяться к любому другому устройству iOS с необходимым аппаратным обеспечением.

Снимите флажок «Включить модульные тесты» и нажмите «Далее». Модульное тестирование не требуется для этого демонстрационного проекта AR, но может оказать большую помощь в реальном жизненном цикле разработки программного обеспечения ( официальная документация Apple по модульному тестированию ).


Последний шаг в этом процессе — выбрать место, где вы хотите сохранить проект на жестком диске, и нажать «Создать».


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

Для получения более подробной информации обратитесь к официальному справочнику и руководству по программированию AVFoundation от Apple.

Процесс импорта фреймворка в проект Xcode 4 прост и, вероятно, хорошо понят, но, тем не менее, для тех, кто не знаком с Xcode 4, это будет продемонстрировано.

Выберите проект «ARDemo» в Xcode 4 Project Navigator. Затем щелкните цель «ARDemo», а затем перейдите на вкладку «Этапы сборки», прежде чем раскрывать раскрывающийся список «Связать двоичные файлы с библиотеками».


Нажмите символ «+» и выберите значение «AVFoundation.framework» из списка. Нажмите «Добавить».


После того, как структура была добавлена ​​и отображена в Навигаторе проекта Xcode, перетащите ее в папку «Frameworks», чтобы сохранить проект в порядке.

Повторите этот процесс, чтобы добавить «CoreMedia.framework» и «CoreVideo.framework».

Теперь, когда у нас есть вышеупомянутые фреймворки в нашем проекте, нам нужно сделать их доступными для нашего кода. Откройте ARDemoViewController.h и добавьте следующую строку:

1
#import <AVFoundation/AVFoundation.h>

Для этого урока нам понадобится объявить два элемента данных и один метод в файле ARDemoViewController.h :

1
2
3
4
5
6
7
8
9
@interface ARDemoViewController : UIViewController
{
    AVCaptureSession *cameraCaptureSession;
    AVCaptureVideoPreviewLayer *cameraPreviewLayer;
}
  
— (void) initializeCaptureSession;
  
@end

В строке 3 объявляется экземпляр AVCaptureSession . Класс AVCaptureSession является основным компонентом, используемым для управления видеовходом, полученным с камеры устройства. В дополнение к управлению входом камеры класс также предоставляет методы делегата, которые делают каждый кадр доступным для вашего приложения для пользовательской обработки. По этой причине мне нравится думать об этом как о медиа-конвейере.

В строке 4 объявляется экземпляр AVCaptureVideoPreviewLayer . Это специальный подкласс CALayer предназначенный для работы с AVCaptureSession путем отображения видеопотока, передаваемого с камеры.

В строке 7 объявляется метод -(void)initializeCaptureSession . Этот метод инициализирует cameraCaptureSession , связывает cameraPreviewLayer с cameraCaptureSession и добавляет cameraCaptureSession в представление.


Остальная часть этого руководства будет посвящена методу -initializeCaptureSession, объявленному на шаге 3. Этот метод следует вызывать из -viewDidLoad поскольку мы хотим, чтобы камера устройства немедленно начала потоковую передачу при загрузке приложения. Давайте продолжим и настроим это:

01
02
03
04
05
06
07
08
09
10
— (void)viewDidLoad
{
    [super viewDidLoad];
    [self initializeCaptureSession];
}
  
-(void)initializeCaptureSession
{
  
}

Если вы проделали большую работу с камерой в UIKit , вы, вероятно, уже знакомы с UIImagePickerController класса UIImagePickerController +availableMediaTypesForSourceType: который возвращает NSArray доступных типов источников. Затем вы можете выполнить итерацию по возвращенному массиву в поисках нужного типа источника, чтобы определить, может ли устройство записывать видео.

Платформа AVFoundation предоставляет аналогичные функциональные возможности для поиска доступных источников ввода (называемых «устройствами захвата»).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Attempt to initialize AVCaptureDevice with back camera
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
AVCaptureDevice *captureDevice = nil;
for (AVCaptureDevice *device in videoDevices)
{
    if (device.position == AVCaptureDevicePositionBack)
    {
        captureDevice = device;
        break;
    }
}
  
// If camera is accessible by capture session
if(captureDevice)
{
    // Desired AVCaptureDevice is available
}
else
{
   // Desired AVCaptureDevice isn’t available.
   UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@»Camera Not Available»
                          message:@»»
                          delegate:nil
                          cancelButtonTitle:@»Okay»
                          otherButtonTitles:nil];
    [alert show];
      
    [alert release];
}

В строке 2 создается массив всех доступных устройств захвата, способных передавать потоковое видео. В строках AVCaptureDevicePositionBack этот массив перебирается в попытке найти устройство со значением позиции AVCaptureDevicePositionBack (если вы предпочитаете завершить этот урок с фронтальной камерой, вы можете вместо этого выполнить поиск AVCaptureDevicePositionFront ).

Оставшаяся часть кода выше просто устанавливает условие, которое тестирует captureDevice чтобы позволить нам динамически отвечать, если по какой-либо причине желаемое устройство недоступно.


Убедившись, что желаемое устройство ввода действительно доступно, давайте продолжим и настроим наш сеанс захвата видео:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
// If camera is accessible by capture session
if(captureDevice)
{
      
    // Allocate camera capture session
    cameraCaptureSession = [[AVCaptureSession alloc] init];
    cameraCaptureSession.sessionPreset = AVCaptureSessionPresetMedium;
      
    // Configure capture session input
    AVCaptureDeviceInput *videoIn = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil];
    [cameraCaptureSession addInput:videoIn];
      
    // Configure capture session output
    AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init];
    [videoOut setAlwaysDiscardsLateVideoFrames:YES];
    [cameraCaptureSession addOutput:videoOut];
    [videoOut release];

В строке 6 выделяется cameraCaptureSession (это будет выпущено позже).

В строке 7 мы указываем, что качество вывода видео, сгенерированного из этого сеанса захвата, должно быть AVCaptureSessionPresetMedium . В официальной документации Apple перечислены следующие доступные варианты для этого параметра:

AVCaptureSessionPresetPhoto
Определяет параметры захвата, подходящие для вывода фотографий высокого качества.
AVCaptureSessionPresetHigh
Определяет параметры захвата, подходящие для высококачественного видео и аудио выхода.
AVCaptureSessionPresetMedium
Определяет параметры захвата, подходящие для вывода видео и аудио битрейтов, подходящих для обмена по WiFi.
AVCaptureSessionPresetLow
Определяет параметры захвата, подходящие для вывода видео и аудио битрейтов, подходящих для совместного использования через 3G.
AVCaptureSessionPreset640x480
Определяет параметры захвата, подходящие для видеовыхода с качеством VGA (640×480 пикселей).
AVCaptureSessionPreset1280x720
Задает параметры захвата, подходящие для видеовыхода с качеством 720p (1280×720 пикселей).

Установка более высокого выходного значения означает, что у вас будет больше данных для обработки и анализа в дополнение к конечному выходному изображению с более высоким визуальным качеством. Однако эти преимущества имеют свою цену: более низкие скорости обработки. При работе с видео или попытке динамического распознавания объектов вы обнаружите, что настройка этого параметра может существенно помочь.

Также обратите внимание, что, хотя доступны определенные предварительные настройки захвата (например, 1280×720, 640×480), обычно рекомендуется использовать одно из более общих значений «High», «Medium» или «Low». Это делает ваше приложение более переносимым и надежным, поскольку оно может работать на устройствах (текущих или будущих!), Которые могут не поддерживать заданное жестко заданное значение.

Строки 8-10 создают объект AVCaptureDeviceInput , используя устройство захвата, которое мы создали ранее, а затем добавляют объект в наш сеанс захвата.

Строки 14 — 17 AVCaptureDeviceOutput объект AVCaptureDeviceOutput и добавляют его в наш сеанс захвата. В строке 15 мы настраиваем videoOut чтобы всегда отбрасывать кадры, полученные с опозданием. Вы должны помнить, что сеанс захвата будет управлять многими кадрами каждую секунду, и из-за различий в загрузке процессора некоторые из этих кадров могут появиться позже, чем другие. Поскольку мы создаем приложение, которое пытается создать живое окно в мир позади iPhone, нам не нужны поздние кадры, поэтому мы отбрасываем их. Мы только хотим обрабатывать и отображать изображения, которые максимально приближены к текущей миллисекунде.


Настроив вход и выход сеанса захвата, пришло время связать слой предварительного просмотра, объявленный в интерфейсе, с видеопотоком сеанса захвата. Это предоставит пользователям цифровое окно реальности вокруг них.

1
2
3
4
5
6
7
8
9
// Bind preview layer to capture session data
cameraPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:cameraCaptureSession];
CGRect layerRect = self.view.bounds;
cameraPreviewLayer.bounds = self.view.bounds;
cameraPreviewLayer.position = CGPointMake(CGRectGetMidX(layerRect), CGRectGetMidY(layerRect));
cameraPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
  
// Add preview layer to UIView layer
[self.view.layer addSublayer:cameraPreviewLayer];

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

Следующая строка устанавливает свойство videGravity . Этот параметр определяет способ визуализации видеокадров в слое предварительного просмотра. Официальная документация Apple описывает следующие возможности:

AVLayerVideoGravityResize
Указывает, что видео должно быть растянуто, чтобы заполнить границы слоя.
AVLayerVideoGravityResizeAspect
Указывает, что проигрыватель должен сохранять пропорции видео и вписывать видео в границы слоя.
AVLayerVideoGravityResizeAspectFill
Указывает, что проигрыватель должен сохранить соотношение сторон видео и заполнить границы слоя.

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

Последняя строка выше отвечает за фактическое добавление CALayer для предварительного просмотра на уровень контроллера представления, делая его видимым для пользователя.


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

1
2
3
    // Begin camera capture
    [cameraCaptureSession startRunning];
}

Когда инициализация сеанса захвата завершена, сейчас, похоже, самое время освободить выделенную память. Сделайте это с помощью следующего кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
— (void)viewDidUnload
{
    [super viewDidUnload];
    [cameraCaptureSession stopRunning];
    [cameraCaptureSession release], cameraCaptureSession = nil;
    [cameraPreviewLayer release], cameraPreviewLayer = nil;
}
  
— (void)dealloc
{
    [cameraCaptureSession stopRunning];
    [cameraCaptureSession release];
    [cameraPreviewLayer release];
          
    [super dealloc];
}

Если вы сохраните, соберете и запустите проект после добавления приведенных выше строк кода, вы сможете увидеть мир вокруг вас прямо на экране iPhone.

Из этого туториала вы узнаете, как использовать инфраструктуру AVFoundation для захвата видео и отображения каждого кадра практически в реальном времени на экране iPhone. Из-за повсеместного распространения видеокамер вокруг нас (а также приложения iPhone Camera) это может показаться не таким уж большим достижением, но это действительно так! Это первый шаг во многих приложениях дополненной реальности: оцифровка представления пользователя о воспринимаемом мире. Отсюда мы можем продолжить в любом количестве направлений — от простого наложения пользовательских представлений на реальный фрейм до фактического манипулирования пиксельными данными мира для улучшения или изменения нашего представления о реальности.

Следующее учебное пособие по Mobiletuts + в этой серии будет продолжено, если взять наше цифровое окно в мир и сделать его немного более интересным. Следите за обновлениями, и спасибо за чтение!