fdo*_*mig 9 c# algorithm math datetime kinect
我正在使用Kinect for Windows SDK来创建一个用于执行的应用程序(使用C#).
基本上我需要跟踪指挥的一只手(通常是右手)并识别他的指挥速度(BPM)以通过MIDI将该值发送到另一个应用程序.
我开始是SkeletonFramesReadyEvent添加JointType.HandRight了DateTime.Now.Ticks时间戳历史List被更新和删除中的第一项.我保持60帧(2秒)的历史.
我通过搜索最后的低点和高点计算BPM Joint.Position.Y,然后计算差值和除法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;
}
Run Code Online (Sandbox Code Playgroud)
我想出了怎么做。我遗漏了一点,计算了手的最高位置和最低位置之间的 BPM,这是错误的。我必须计算最后两个低点之间的时间差才能得到正确的结果。
正确的方法是找到最后一个峰值的起点。从那里移动到最后一个低点,这是计算差异的第一个点。移动到下一个峰值并再次下降到下一个低点,这是计算差异的第二个点。
原理如下图所示

这会产生一个很好的 BPM,计算如下:
var ticks = Math.Abs(firstLow.Ticks - secondLow.Ticks);
var elapsedTime = new TimeSpan(ticks);
var bpm = (int) (60000/elapsedTime.TotalMilliseconds);
Run Code Online (Sandbox Code Playgroud)
不管怎样,谢谢你的参与。
| 归档时间: |
|
| 查看次数: |
673 次 |
| 最近记录: |