【问题标题】:Calculate BPM from Kinect sensor data根据 Kinect 传感器数据计算 BPM
【发布时间】:2012-06-29 16:08:32
【问题描述】:

我正在努力使用 Kinect for Windows SDK 创建一个应用程序来进行(使用 C#)。

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

我开始使用SkeletonFramesReadyEvent 将带有DateTime.Now.Ticks 时间戳的JointType.HandRight 添加到历史记录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;
}

【问题讨论】:

  • 你得到什么结果,你期望什么结果?
  • 调试:BPM = 512,elapsedMS:328 调试:BPM = 182,elapsedMS:-322 调试:BPM = -186,elapsedMS:-337 调试:BPM = -178,elapsedMS:299 调试: BPM = 200, elapsedMS: 683 DEBUG: BPM = 87, elapsedMS: -378 DEBUG: BPM = -158, elapsedMS: 92
  • 首先,您可能应该使用Math.Abs() 来计算ticks 的差异(这将说明负值)。根据文档,Timestamp 以毫秒为单位,而不是滴答声,因此请使用TimeSpan.FromMilliseconds(ticks) 而不是new TimeSpan(ticks)(也可能重命名ticks
  • 我对蜱虫表示歉意,您的问题被标记为 kinect,因此假设应用了 kinect sdk 文档。
  • 只需将您的数据以 CSV 格式输出到文件并在 Excel 中绘制...

标签: c# algorithm math datetime kinect


【解决方案1】:

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

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

原理如下图所示

这会产生一个很好的 BPM 计算结果,如下所示:

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

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

感谢您的参与。

【讨论】:

  • 如果您的数据嘈杂,那么检测到最小值将是可疑的。您很可能只差一个刻度就得到局部最小值。这就是为什么我说你可能需要平滑你的数据,(它可能 Kinect 正在为你平滑它 - 但没有看到数据图表很难分辨。)它也很可能是伴随着轻微的噪音,你所拥有的大部分时间都可以工作 - 然后失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
  • 2013-08-17
  • 1970-01-01
  • 1970-01-01
  • 2015-05-05
  • 2012-08-23
  • 1970-01-01
相关资源
最近更新 更多