Это кросс-сообщение из моего блога, исходное сообщение вы можете найти здесь.
В наши дни почти трудно не читать о машинном обучении, и эта тенденция будет только усиливаться. Машинное обучение открывает новые мощные возможности для приложений для смартфонов, от классификации изображений до распознавания лиц.
Он также может определять, как кто-то взаимодействует со своим смартфоном.
В этом проекте показано, как использовать Набор инструментов распознавания жестов для определения того, как пользователь перемещает свой телефон в физическом пространстве. (Я написал здесь краткое руководство о том, как начать интеграцию GRT в проект приложения для iPhone).
Акселерометр iPhone будет использоваться в качестве входа для системы распознавания жестов. Это все, чтобы приложение извлекало жесты из того, как пользователь перемещает iPhone. Данные будут переданы в классификатор, который является частью конвейера GRT, который предскажет, какой жест выполняет пользователь. Чтобы получить доступ к этим данным датчика, приложение будет использовать CoreMotion Framework от Apple. Прекрасные люди из NSHipster имеют хороший обзор структуры здесь.
Приложение будет иметь два режима и два контроллера представления соответственно. Первый, показанный ниже, - это тренировочный режим. Пока мы делаем соответствующий жест на телефоне, красная кнопка «Поезд» удерживается. Пока он удерживается, данные с акселерометра телефона сохраняются в структуре данных, которую мы будем использовать для обучения нашего конвейера. Как только кнопка перестает удерживаться, этот процесс останавливается. Контроллер сегмента будет служить способом установить метку класса для выполняемого жеста.

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

Делегат приложения содержит глобальный экземпляр конвейера GRT, поэтому к нему могут получить доступ оба контроллера представления:
var pipeline: GestureRecognitionPipeline?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//Create an instance of a gesture recognition pipeline to be used as a global variable, accesible by both our training and prediction view controllers
self.pipeline = GestureRecognitionPipeline()
return true
}
Класс AccelerometerManager позволит двум контроллерам представления получить доступ к координатам X, Y и Z с акселерометра телефона. Метод запуска, показанный ниже, создаст объект, который вернет данные акселерометра:
func start(_ accHandler: @escaping (_ x: Double, _ y: Double, _ z: Double) -> Void) { let handler: CMAccelerometerHandler = {(data: CMAccelerometerData?, error: Error?) -> Void in guard let acceleration = data?.acceleration else { print("Error: data is nil: \(String(describing: error))") return } accHandler(acceleration.x, acceleration.x, acceleration.z) } motionManager.startAccelerometerUpdates(to: motionQueue, withHandler: handler) }
Метод остановки остановит этот процесс, так что приложение будет собирать данные только с акселерометра телефона, когда конвейер обучается, или выполняет распознавание в реальном времени.
Контроллер просмотра тренировок
Ядром контроллера просмотра тренировок является функция TrainBtnPressed. Он вызывается всякий раз, когда удерживается красная кнопка «Поезд», принимает координаты акселерометра и создает из них вектор. Этот вектор затем отправляется в функцию «addSamplesToClassificationData» конвейерной оболочки.
func TrainBtnPressed(_ sender: Any) {
trainButton.isSelected = true
let gestureClass = self.gestureSelector.selectedSegmentIndex
accelerometerManager.start({ (x, y, z) -> Void in
//Add the accellerometer data to a vector, which is how we'll store the classification data
let vector = VectorFloat()
vector.clear()
vector.pushBack(x)
vector.pushBack(y)
vector.pushBack(z)
print("x", x)
print("y", y)
print("z", z)
print("Gesture class is %@", gestureClass);
self.pipeline!.addSamplesToClassificationData(forGesture: UInt(gestureClass), vector)
})
}
После записи данных жеста и нажатия кнопки «Сохранить конвейер» данные конвейера и обучения жестам сохраняются.
Контроллер представления прогнозов
После сохранения конвейера приложение можно использовать в режиме прогнозирования в реальном времени. Этот контроллер представления принимает данные акселерометра и передает их конвейеру с помощью функции «прогнозирования».
Здесь происходит то, что конвейер сравнивает входящие данные акселерометра с помеченными данными обучения и делает прогноз относительно того, какой жест сделал пользователь со своим телефоном. Эти данные представлены свойством classLabel.
Приложение сначала убедится, что оно может успешно загрузить файл конвейера train.grt и файлы данных классификации trainingData.csv. Если это возможно, то выполняется вызов метода конвейера train, который находится в оболочке Objective-C для GRT:
- (BOOL)trainPipeline {
*self.trainingData = self.classificationData->split(80);
BOOL trainSuccess = self.instance->train( *(self.trainingData) );
...
return trainSuccess;
}
Вернувшись в контроллер прогнозирования, метод performGesturePrediction () принимает координаты акселерометра в реальном времени и помещает их в вектор:
func performGesturePrediction() {
accelerometerManager.start { (x, y, z) -> Void in
self.vector.clear()
self.vector.pushBack(x)
self.vector.pushBack(y)
self.vector.pushBack(z)
...
Затем этот вектор передается в оболочку конвейера Objective-C:
self.pipeline?.predict(self.vector)
Остальная часть функции получает прогнозируемую метку класса из конвейера и отображает прогнозируемый результат жеста в пользовательском интерфейсе:
...
DispatchQueue.main.async {
self.updateGestureCountLabels(gesture: (self.pipeline?.predictedClassLabel)!)
print("PRECITED GESTURE", self.pipeline?.predictedClassLabel ?? 0);
self.graphView.addData([x, y, z])
}
}
}
ИСПОЛЬЗОВАНИЕ ПРИЛОЖЕНИЯ
При реализации системы распознавания жестов в реальном времени следует учитывать одно важное соображение - обучить систему тому, что не распознавать. В этом случае состояние покоя телефона (когда с ним не выполняется жест) - это когда телефон удерживается неподвижно:

Мне удалось обучить систему распознавания жестов распознавать быстрое встряхивание телефона:

… Смахивание сбоку:

… И «волновое движение»:

Если вы в конечном итоге воспользуетесь этой демонстрацией, чтобы распознать интересные жесты, не стесняйтесь делиться своими результатами в комментариях! Помните, что надежность системы распознавания жестов будет зависеть от того, насколько хорошо вы тренируетесь для определенных жестов, которые хотите распознавать.
Код проекта находится на GitHub здесь.