从Kinect传感器数据计算BPM

时间:2012-06-29 16:08:32

标签: c# algorithm math datetime kinect

我正在使用Kinect for Windows SDK来创建一个用于执行的应用程序(使用C#)。

基本上我需要跟踪指挥的一只手(通常是右手)并识别他指挥的速度(BPM)以通过MIDI将此值发送到另一个应用程序。

我开始使用SkeletonFramesReadyEventJointType.HandRight添加DateTime.Now.Ticks时间戳到历史记录List,并更新并删除第一个条目。我保留了60帧(2秒)的历史。

我通过搜索Joint.Position.Y的最后一个低点和高点来计算BPM,然后计算差值并除以bpm = 60*ticksPerSecond/diff。但结果是错误的。还有另一种方法吗?我错过了什么?

这是我到目前为止所使用的:

public int DetectBPM(JointType type)
{
    // we have not history yet
    if (!HasHistory()) return 0;

    // only calculate every second
    var detectTime = DateTime.Now.Second;
    if (_lastBPM != 0 && _lastBPMDectect == detectTime) return _lastBPM;

    // search last high/low boundaries
    var index = (int) type;
    var list = History[index];
    var i = list.Count - 1;

    var lastHigh = list[i];
    var lastLow = list[i];

    // shift to last peak first
    while (i > 0 && list[i].Joint.Position.Y >= list[i - 1].Joint.Position.Y) i--;

    // find last low
    while (i >= 0 && lastLow.Joint.Position.Y >= list[i].Joint.Position.Y) lastLow = list[i--];

    // find last high
    while (i >= 0 && lastHigh.Joint.Position.Y <= list[i].Joint.Position.Y) lastHigh = list[i--];

    var ticks = lastLow.Timestamp - lastHigh.Timestamp;
    var elapsedTime = new TimeSpan(ticks);

    var bpm = (int) (60000/elapsedTime.TotalMilliseconds);

    Console.WriteLine("DEBUG: BPM = " + _lastBPM + ", elapsedMS: " + elapsedTime.TotalMilliseconds);

    _lastBPMDectect = detectTime;
    _lastBPM = bpm;

    return _lastBPM;
}

1 个答案:

答案 0 :(得分:2)

我想出了怎么做。我错过了一个点并计算了手的峰值和低位之间的BPM,这是错误的。我必须使用最后两个低点之间的时间差来获得正确的结果。

正确的方法是找到最后一个峰值的说明点。从那里移到最后一个低点,这是计算差异的第一点。移动到下一个峰值并再次下降到下一个低点,这是计算差异的第二个点。

原理如下图所示

BPM calucaltion schema

这样可以得到一个很好的BPM计算结果:

var ticks = Math.Abs(firstLow.Ticks - secondLow.Ticks);
var elapsedTime = new TimeSpan(ticks);

var bpm = (int) (60000/elapsedTime.TotalMilliseconds);

感谢您的参与。