Написание приложения под Kinect

в 11:27, , рубрики: .net, Kinect, Microsoft Kinect, здоровый образ жизни, Компьютерное зрение, метки: , , ,

Вступление

Как долго вы проводите время за компьютером в день? Час, два, пять, может двадцать? Я уверен что вряд ли вы делаете перерыв в работе особенно если вы серьёзный дядька очень заняты важным делом. Но если у вас есть Kinect, то вы можете написать для него приложение которое позволит поддерживать себя в отличной форме.

В здоровом теле — здоровый дух

Теперь — самое главное! О том, как написать программу, которая будет использовать возможности сенсора, а заодно и поддерживать бодрость тела: после часа работы за компьютером она заблокирует клавиатуру и мышь и не позволит пользоваться вновь, пока не сделаешь пару приседаний.
image
В уже установленном скорее всего Visual Studio есть примеры проектов (как на C++, так и на C#), которые можно дописать для своих задач. Но эти примеры несколько запутаны, и будет проще воспользоваться оберткой, которую написал греческий студент Вангос Птернеас. Найти его библиотеку — Nui.Vision.dll — можно на этой странице. С ней строчек кода понадобится гораздо меньше.

Приступим к созданию

Сначала создадим в Visual Studio проект WPF Application и добавим в него ссылки на библиотеки OpenNi.net.dll (она находится в той папке, куда установлен OpenNI) и Nui.Vision.dll (её можно положить в папку проекта).

Теперь разберемся с работой сенсора. В описании формы MainWindow.xaml выставим размер 662x520 и добавим к ней изображение, в которое будет выводиться картинка с сенсора, и холст, на который будет выводиться дополнительная информация:

<Image Name="imgCamera"/>
<Canvas Name="LayoutRoot"/>

Объявляем пространства имен:

using System.ComponentModel; // нужен для обработки в фоне
using Nui.Vision; // работа с кинектом

В конструкторе инициализируем обработчик событий:

// инициализируем объект и подгружаем конфиги кинекта
_skeleton = new NuiUserTracker("SamplesConfi g.xml");
// объявляем функцию, которая будет обрабатывать
// событие перемещения пользователя
_skeleton.UsersUpdated += new NuiUserTracker.
UserListUpdatedHandler(Skeleton_UsersUpdated);

Теперь в переменной NuiUserListEventArgs.Users представлены все обнаруженные пользователи и набор координат всех распознанных частей их тел. Далее напишем обработчик события смены координат пользователя. Как только у тебя появляется ненулевое значение вертикальной координаты шеи пользователя — считай, что он готов приседать. Потом добавим две линии. Одна чуть ниже шеи, а другая — чуть выше пояса. Одним приседанием будет считаться двойное пересечение обеих линий: сначала — сверху вниз, а потом — снизу вверх. Отслеживается пересечение линий шеи (хотя визуально она где-то на груди). Такой вариант не идеальный — можно схалтурить, нагибаясь, или подойдя поближе к сенсору. Если кто знает решение добро пожаловать в комментарии.

// проделываем все манипуляции для каждого пользователя
// (хотя приседать они будут под одну гребенку)
foreach (var user in e.Users)
{ // если впервые нашлась шея
if ((topY == 0) && (user.Neck.Y !=0) )
{ // определяем положение верхней линии
topY = user.Neck.Y+20;
Line topLine = new Line
{ // определяем верхнюю линию
Y1 = topY,X1 = 0, Y2 = topY, X2 = 662,Stroke = new SolidColorBrush(Colors.Red),
StrokeThickness = 4 };

// рисуем верхнюю линию на холсте
LayoutRoot.Children.Add(topLine);
// определяем положение нижней линии
bottomY = user.Torso.Y + 20;
Line bottomLine = new Line
{ // определяем нижнюю линию
Y1 = bottomY, X1 = 0, Y2 = bottomY, X2 = 662,Stroke = new SolidColorBrush(Colors.Blue),StrokeThickness = 4 };
// рисуем нижнюю линию на холсте
LayoutRoot.Children.Add(bottomLine);
// рисуем шею на холсте
LayoutRoot.Children.Add(ellipse); }

При каждом изменении координат нужно проверять, не произошло ли приседания:

ellipse.Margin= new Thickness(user.Neck.X, user.Neck.Y,
0, 0); //перемещаем кружочек вслед за шеей

// ставим флажок верхнего положения
if (user.Neck.Y+5 < topY) topPosition = true;

// ставим флажок нижнего положения
if (user.Neck.Y + 25 > bottomY) bottomPosition = true;

if (topPosition && bottomPosition) { // если оба флага есть
numOfBobs++; // половину приседания в копилку

topPosition = false; // сбрасываем флажки
bottomPosition = false;

}
// если полуприседаний набралось двадцать штук — значит все,выключаем программу
if (numOfBobs >= 20) {
Application.Current.Shutdown(); // выходим из программы
}

Осталось разобраться с таймером и блокировкой клавиатуры и мыши. Сперва нужно добавить еще одно пространство имен:

// работа с неуправляемым кодом, понадобится для блокировки клавиатуры
using System.Runtime.InteropServices;

public partial class NativeMethods {
[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "BlockInput")]
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool BlockInput(
[System.Runtime.InteropServices.MarshalAsAttribute(
System.Runtime.InteropServices.UnmanagedType.Bool)]
bool fBlockIt);

}

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

using System.Timers;

Объявить таймер:

private static System.Timers.Timer TheTimer;

А дальше запустить его по нажатию кнопки:

private void button1_Click(object sender, RoutedEventArgs e)
{
// ставим таймер на час
TheTimer = new System.Timers.Timer(3600000);
// как пройдет — блокируем комп<code>
<code>TheTimer.Elapsed += new ElapsedEventHandler(BlockPC);

TheTimer.Enabled = true;
}

А при срабатывании таймера всё будет блокироваться и открываться окошко с видео с кинекта:

void BlockPC(object source, ElapsedEventArgs e){
App.NativeMethods.BlockInput(true); // блокируем ввод
// создаем экземпляр формы с картинкой от сенсора
MainWindow w = new MainWindow();
w.Show(); }// и показываем ее

А при срабатывании таймера будет блокироваться пользовательский ввод и открываться окошко с видео с кинекта:

void BlockPC(object source, ElapsedEventArgs e) {
App.NativeMethods.BlockInput(true); // блокируем ввод
// создаем форму с картинкой от сенсора
MainWindow w = new MainWindow();
w.Show(); }// и показываем её

Не забудьте добавить отмену блокировки перед выходом:

// возвращаем пользователю управление
App.NativeMethods.BlockInput(false);
Удачи в программировании.

Автор: azarovalex

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js