Алгоритм постепенного перемещения курсора - Kinect SDK - PullRequest
4 голосов
/ 08 сентября 2011

Я создаю приложение Kinect SDK WPF и использую Kinect для перемещения объекта «курсор» / рука.

Проблема, с которой я сталкиваюсь, состоит в том, что при 30 кадрах в секунду курсор фактически прыгает вокругнемного ошибочно из-за точности Kinect (то есть, держа руку неподвижно, объект перемещается в пределах 5px).

Я планирую написать алгоритм, который не просто перемещает X / Y моего«Курсор» спринтится в правильную позицию на экране, но ведет себя больше как «переместить руку к этой координате X / Y», так что это более плавное движение.

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

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

Ответы [ 3 ]

4 голосов
/ 08 сентября 2011

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

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

Пример реализации для дискретных по времени значений будет от здесь (первоначально wikipedia ):

static final float ALPHA = 0.15f;

protected float[] lowPass( float[] input, float[] output ) {
    if ( output == null ) return input;

    for ( int i=0; i<input.length; i++ ) {
        output[i] = output[i] + ALPHA * (input[i] - output[i]);
    }
    return output;
}

Вы можете поместить в эту функцию последние значения обоих компонентов X и Y ваших векторов положения, чтобы сгладить их (input[0] для X и input[1] для Y, output[0] и output[1] являются результатами предыдущего вызова функции).

Как я уже сказал, вы должны найти хороший баланс для коэффициента сглаживания ALPHA (0 ≤ ALPHA ≤ 1) :

  • Слишком большой, и сигнал не будет достаточно сглаженным, эффект будет недостаточным
  • Слишком маленький и сигнал будет сглажен «слишком сильно», курсор будет отставать от пользователейдвижение, слишком большая инерция

(Если вы посмотрите на формулу newout = out + alpha * (in - out), вы увидите, что при альфа-значении 0 вы просто снова берете старое значение out, поэтому значение будетникогда не меняются, хотя со значением 1 у вас есть newout = out + in - out, что месли вы ничего не сглаживаете, но всегда принимаете самое новое значение)

4 голосов
/ 13 сентября 2011

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

float currentX = ..., currentY = ..., targetX = ..., targetY = ...; 
float diffX = targetX - currentX;
float diffY = targetY - currentY;
float delta = 0.5f; // 0 = no movement, 1 = move directly to target point. 

currentX = currentX + delta * diffX;
currentY = currentY + delta * diffY;

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

В соответствующей заметке вы смотрели параметры сглаживания скелета Kinect? На самом деле вы можете позволить SDK обрабатывать некоторые из фильтров.

0 голосов
/ 08 сентября 2011

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

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

Надеюсь, это поможет!

...