protected MotionSuper _successor = null; // 下一个处理者 #endregion Fields #region Methods /// <summary> /// 处理请求数据 /// </summary> /// <param name="data">传入的特征数据</param> /// <returns>处理成功返回true,否则返回false</returns> public bool HandleData(FeatureData data) { if (Recognise(data)) { //// 识别到连续RecognizedCountThreshold个成功后发送命令,而且只发送一次 //if (++_recognizedCount == RecognizedCountThreshold) // 特别注意是先加 //{ // // convert and send // SendCommand(); // //Thread.Sleep(1000); //} ++_recognizedID; // convert and send try { SendCommand(); } catch (System.Exception ex) { throw new Exception(ex.Message); } return true; } else { // _recognizedCount = 0; // 恢复识别计数器 if (_successor != null) // 如果存在后继者则处理 { return _successor.HandleData(data); } } return false; }
/// <summary> /// 处理数据请求 /// </summary> /// <param name="data">传入特征数据</param> /// <returns>返回识别代码,未识别返回-1</returns> public int HandleDataEx(FeatureData data) { if (Recognise(data)) { ++_recognizedID; int cmdCode; try { cmdCode = SendCommand(); } catch (System.Exception ex) { throw new Exception(ex.Message); } return cmdCode; } else { if (_successor != null) // 如果存在后继者则处理 { return _successor.HandleDataEx(data); } } return -1; }
protected override bool Recognise(FeatureData data) { switch (_motionState) { case MotionState.Initial: float footHeight = data.CalculateDifferY(JointType.AnkleRight, JointType.AnkleLeft); // 判断是否抬高脚data.CompareThresholdY(JointType.AnkleRight, JointType.AnkleLeft, 15) == 1 if (footHeight > MinFootHeight && footHeight < MaxFootHeight) // 用Y判断脚抬高度,脚离地阈值为15 { _motionState = MotionState.Invalid;// 标记为无效,等待放下脚恢复初始状态 if (data.CompareThresholdZ(JointType.AnkleRight, JointType.HipRight, 30) == 0 && // 用Z排除非前踢腿 data.CompareThresholdX(JointType.AnkleRight, JointType.HipRight, 15) == 0) // 用X排除非左右侧踢腿 { return true; } } break; default: // 放下脚恢复初始状态 if (data.CompareThresholdY(JointType.AnkleRight, JointType.AnkleLeft, 5) == 0) { _motionState = MotionState.Initial; } break; } return false; }
protected override bool Recognise(FeatureData data) { // 如果另一只手不在初始位置,则不识别 if (data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == 1) { _motionState = MotionState.Invalid; return false; } switch(_motionState) { case MotionState.Initial: // 手超过一定位置 if (data.CompareThresholdY(JointType.HandRight, JointType.ShoulderLeft, 0) == 1) { // 用肩中心到脊椎的距离大致估计手的比例,确保身高不影响,超出身体指定的范围标记为无效,此时刚好为到Y轴的距离 // 并且手在身体附近 if (data.CalculateDifferX(JointType.HandRight, JointType.ShoulderCenter) < 5 || (data.HandRight2BodyHorizontalDistance < data.ShoulderCenter2SpineHeight && data.CalculateSpaceDistance(JointType.HandRight, JointType.ShoulderLeft) < data.ShoulderCenter2SpineHeight)) { _motionState = MotionState.Valid; } else { _motionState = MotionState.Invalid; } } break; case MotionState.Valid: // 达到第一个有效点后 // 判断是否超过了头 if (data.CompareThresholdY(JointType.HandRight, JointType.Head, 0) == 1) { _motionState = MotionState.Valid2; } break; case MotionState.Valid2: // 第二个有效点 if (data.CompareThresholdY(JointType.HandRight, JointType.ShoulderRight, 15) == 0) // 经过了肩的位置,表明正放下 { _motionState = MotionState.Invalid; // 无论结果如何都无效 // 手是否伸直的,上身的高度,用于近视计算手的比例 if (data.HandRight2BodyHorizontalDistance > data.Head2HipCenterHeight*0.8) { return true; } } break; default: break; } // 当手放下时 if (_motionState != MotionState.Initial && data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } return false; }
private const float LegRadianThreshold = 0.57f; //30, 0.64f; //弧度阈值;40度约为0.64左右,45度约为0.707 #endregion Fields #region Methods protected override bool Recognise(FeatureData data) { switch (_motionState) { case MotionState.Initial: // 判断是否抬高脚 if (data.CompareThresholdY(JointType.AnkleRight, JointType.AnkleLeft, 10) == 1) // 用Y判断脚抬高度,脚离地阈值为10 { _motionState = MotionState.Valid; } break; case MotionState.Valid: // 区别抬脚动作 if (data.CompareThresholdZ(JointType.AnkleRight, JointType.HipRight, 30) == 0 && data.CompareThresholdX(JointType.AnkleRight, JointType.HipRight, 15) == 0) { _motionState = MotionState.Invalid; return false; } // 大概的腿长,从踝开始计算 float legLength = data.CalculateDifferY(JointType.HipLeft, JointType.AnkleLeft); if (legLength <= 0) // 腿长不适合理论数据 { return false; } // 在x和z轴上的映射投影距离差值 float ankleDifferX = Math.Abs(data.CalculateDifferX(JointType.AnkleRight, JointType.AnkleLeft)); float ankleDifferZ = Math.Abs(data.CalculateDifferZ(JointType.AnkleRight, JointType.AnkleLeft)); if (ankleDifferX >= ankleDifferZ) // 排除向前或后踢的情况 { // 计算腿抬起后裸相差的水平距离 float ankleHorizontalDistance = (float)Math.Sqrt(ankleDifferX * ankleDifferX + ankleDifferZ * ankleDifferZ); // 计算腿抬起的弧度 float legRadian = ankleHorizontalDistance / legLength; // 当抬起角度超过弧度阈值后生效 if (legRadian > LegRadianThreshold) { _motionState = MotionState.Invalid; return true; } } else { _motionState = MotionState.Invalid; } break; default: // 放下脚恢复初始状态 if (data.CompareThresholdY(JointType.AnkleRight, JointType.AnkleLeft, 5) == 0) { _motionState = MotionState.Initial; } break; } return false; }
protected override bool Recognise(FeatureData data) { // 当另一只手也举起则无效 if (data.CompareThresholdY(JointType.HandLeft, JointType.ShoulderLeft, 0) == 1) { _motionState = MotionState.Invalid; return false; } switch (_motionState) { case MotionState.Initial: // 当超过肩开始生效 if (data.CompareThresholdY(JointType.HandRight, JointType.ShoulderLeft, 0) == 1) { // 太近了则无效,区别于划圆 if (data.CalculateDifferX(JointType.HandRight, JointType.ShoulderCenter) < 5 || (data.HandRight2BodyHorizontalDistance < data.ShoulderCenter2SpineHeight && data.CalculateSpaceDistance(JointType.HandRight, JointType.ShoulderLeft) < data.ShoulderCenter2SpineHeight)) { _motionState = MotionState.Invalid; } else { _motionState = MotionState.Valid; } } break; case MotionState.Valid: // 手举起后肘关节与头的相对位置 //if (data.CompareThresholdY(JointType.ElbowRight, JointType.Head, 13) == 0 && // data.CompareThresholdX(JointType.ElbowRight, JointType.Head, 33) == 0) if (data.CompareThresholdY(JointType.HandRight, JointType.Head, 8) == 1) { _motionState = MotionState.Invalid; return true; } //else if (data.HandRight2BodyHorizontalDistance > 1.1 * data.Head2HipCenterHeight) // 在有效状态下,超出身体指定的范围标记为无效,可能是从侧面举起手的 //{ // // 水平距离的阈值,大致估计手的比例,确保身高不影响(可用1.8 * data.ShoulderCenter2SpineHeight) // _motionState = MotionState.Invalid; //} break; default: break; } // 手放下来后恢复初始状态 if (_motionState != MotionState.Initial && data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } return false; }
protected override bool Recognise(FeatureData data) { switch (_motionState) { case MotionState.Initial: // 手超过了脊椎的位置 if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == 1 && data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == 1) { // 用肩中心到脊椎的距离替代肩宽,理论上比肩宽大一些 // 并且两手距离近 if (data.Hand2HandHorizontalDistance < data.ShoulderCenter2SpineHeight) { _motionState = MotionState.Valid; } //else //{ // _motionState = MotionState.Invalid; // W.S. //} } break; case MotionState.Valid: // 上身的高度,用于近视计算手的比例 WS (此处不知双手平推和双手展开的区别,先区别一个双手交叉吧) // 当两手距离超过阈值后识别成功 if (data.Hand2HandHorizontalDistance > 2 * data.ShoulderCenter2HipCenterHeight ) { //_motionState = MotionState.Invalid; // 无论是否成功识别者标记为无效状态 W.S. _motionState = MotionState.Initial; // 为了多次识别 // 区别于双手向下的动作,只有在肩的上方 if (data.CompareThresholdY(JointType.HandRight, JointType.ShoulderRight, 5) >= 0 && data.CompareThresholdY(JointType.HandLeft, JointType.ShoulderLeft, 5) >= 0 ) { return true; } } break; default: break; } // 如果手抬起太高,则抬起失效 if (_motionState != MotionState.Invalid && (data.CompareThresholdY(JointType.HandRight, JointType.ShoulderCenter, 15) == 1 || data.CompareThresholdY(JointType.HandLeft, JointType.ShoulderCenter, 15) == 1)) { _motionState = MotionState.Invalid; } // 当手放下时恢复初始 if (_motionState != MotionState.Initial) { if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1 || data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } } return false; }
protected override bool Recognise(FeatureData data) { // 用肩中心到脊椎的距离替代肩宽,理论上比肩宽大一些 float minHorizontalDistanceThreshold = data.ShoulderCenter2SpineHeight; switch (_motionState) { case MotionState.Initial: // 手是否在经过肩附近 if (data.CompareThresholdY(JointType.HandRight, JointType.ShoulderRight, 15) == 0 && data.CompareThresholdY(JointType.HandLeft, JointType.ShoulderRight, 15) == 0 && data.Hand2HandHorizontalDistance < minHorizontalDistanceThreshold) // 并且两手距离很近 { _motionState = MotionState.Valid; } break; case MotionState.Valid: // 上身的高度,用于近视计算手的比例 // 当两手距离超过阈值后识别成功 if (data.Hand2HandHorizontalDistance > /*2 * */data.ShoulderCenter2HipCenterHeight) { // 判断是否高于头部 if (data.CompareThresholdY(JointType.HandRight, JointType.Head, 0) == 1 && data.CompareThresholdY(JointType.HandLeft, JointType.Head, 0) == 1) { _motionState = MotionState.Initial; // 识别后标记为初始状态 return true; } else if (data.Hand2HandHorizontalDistance > 2 * data.ShoulderCenter2HipCenterHeight)// && //data.CompareThresholdY(JointType.HandRight, JointType.ShoulderRight, 15) == 0 && //data.CompareThresholdY(JointType.HandLeft, JointType.ShoulderRight, 15) == 0) { _motionState = MotionState.Initial; // 排除从两边抬起手臂,还可排除手低的情况 } } break; default: break; } // 当手放下时恢复初始状态 if (_motionState != MotionState.Initial && (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1 || data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1)) { _motionState = MotionState.Initial; } // 当两手合在一起后超过头设置 //if (_motionState != MotionState.Initial && // data.Hand2HandHorizontalDistance < minHorizontalDistanceThreshold && // (data.CompareThresholdY(JointType.HandRight, JointType.Head, 0) == 1 || // data.CompareThresholdY(JointType.HandLeft, JointType.Head, 0) == 1)) //{ // _motionState = MotionState.Initial; //} return false; }
private const double TimeMillisecondsThreshold = 850d; // 时间阈值,以毫秒计算 #endregion Fields #region Methods protected override bool Recognise(FeatureData data) { // 如果另一只手不在初始位置,则不识别 if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == 1) { _motionState = MotionState.Invalid; return false; } switch (_motionState) { case MotionState.Initial: // 如果手超过肩位置,则手抬起开始生效 if (data.CompareThresholdY(JointType.HandLeft, JointType.ShoulderLeft, 0) == 1) { _dtBegin = DateTime.Now; // 获取开始时间 _motionState = MotionState.Valid; } break; case MotionState.Valid: // 如果生效了,则判断是否回到初始位置,如果是,则识别成功 if (data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; _dtEnd = DateTime.Now; // 获取截止时间 // 如果时间差小于一定的阈值则识别 if (_dtEnd.Subtract(_dtBegin).TotalMilliseconds < TimeMillisecondsThreshold) { return true; } } break; default: // 其他状态回到了初始位置,则重置状态为初始状态 if (data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } break; } if (_motionState != MotionState.Invalid) { // 如果手抬起太高,则抬起失效 if (data.CompareThresholdY(JointType.HandLeft, JointType.Head, 8) == 1) { _motionState = MotionState.Invalid; } // 超出身体指定的范围标记为无效,此时刚好为到Y轴的距离 if (data.HandLeft2BodyHorizontalDistance > data.Head2HipCenterHeight) { _motionState = MotionState.Invalid; } } return false; }
protected override bool Recognise(FeatureData data) { // 如果另一只手不在初始位置,则不识别 if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == 1) { _motionState = MotionState.Invalid; return false; } switch (_motionState) { case MotionState.Initial: // 用肩中心到脊椎的距离大致估计手的比例,确保身高不影响,超出身体指定的范围标记为无效,此时刚好为到Y轴的距离 // 手超过了脊椎的位置并且手在身体附近 if (data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == 1 && data.HandLeft2BodyHorizontalDistance < data.ShoulderCenter2SpineHeight) { _motionState = MotionState.Valid; } break; case MotionState.Valid: // 上身的高度,用于近视计算手的比例 if (data.HandLeft2BodyHorizontalDistance > data.Head2HipCenterHeight) { _motionState = MotionState.Initial; return true; } break; default: break; } // 如果手抬起太高,则抬起失效 if (_motionState != MotionState.Invalid && data.CompareThresholdY(JointType.HandLeft, JointType.Head, 0) == 1) { _motionState = MotionState.Invalid; } // 当手放下时 if (_motionState != MotionState.Initial) { if (data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } else if (_motionState == MotionState.Invalid // 当因为另一只手抬起导致状态无效时 && data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } } return false; }
protected override bool Recognise(FeatureData data) { // 计算两脚高度差 float ankleDifferY = Math.Abs(data.CalculateDifferY(JointType.AnkleRight, JointType.AnkleLeft)); // 计算两脚的绝对坐标 float absoluteAnkleRightY = data.RelativeJoints[(int)JointType.AnkleRight].Position.Y + data.AbsoluteOrigin.Y; float absoluteAnkleLeftY = data.RelativeJoints[(int)JointType.AnkleLeft].Position.Y + data.AbsoluteOrigin.Y; bool tracked = data.IsJointTracked(JointType.AnkleRight); // 两脚绝对坐标Y的较小值 float minAbsoluteAnkleY = Math.Min(absoluteAnkleLeftY, absoluteAnkleRightY); // 当一只脚超过另一脚时 if (ankleDifferY > MaxHeightThreshold) { // 当想站上某个高处时即开始准备重设地面,获取较大值 _groundLevel = Math.Max(absoluteAnkleLeftY, absoluteAnkleRightY); } switch(_motionState) { case MotionState.Initial: // 当两脚高度差不超过阈值时 if (ankleDifferY < MinHeightThreshold) { // 获取左右脚以及地面中最小的值来重设地面 _groundLevel = Math.Min(minAbsoluteAnkleY, _groundLevel); // 直接判断 if (minAbsoluteAnkleY - _groundLevel > JumpHeightThreshold && tracked) { // 重置地面,用于判断是否开始落下,否则跳太高会二次识别 _groundLevel = minAbsoluteAnkleY; _counter = 0; _motionState = MotionState.Invalid; return true; } } break; default: if ( minAbsoluteAnkleY < _groundLevel) // 当开始落下时才生效 { _motionState = MotionState.Initial; } else if (++_counter >= CounterThreshold) // 可能跳到了一个较高的地方,需要一段时间来重置 { _counter = 0; _groundLevel = minAbsoluteAnkleY; _motionState = MotionState.Initial; } break; } return false; }
protected override bool Recognise(FeatureData data) { switch (_motionState) { case MotionState.Initial: // 手超过了脊椎的位置 if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == 1 && data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == 1 ) { // 并且两手距离很远(上半身的高度,用于近视计算手的比例) if (data.Hand2HandHorizontalDistance > 2 * data.ShoulderCenter2HipCenterHeight) { _motionState = MotionState.Valid; } else { _motionState = MotionState.Invalid; } } break; case MotionState.Valid: // 用肩中心到脊椎的距离替代肩宽,理论上比肩宽大一些 if (data.Hand2HandHorizontalDistance < data.ShoulderCenter2SpineHeight) { _motionState = MotionState.Invalid; // 识别后标记为无效状态 return true; } break; default: break; } // 如果手抬起太高,则抬起失效 if (_motionState != MotionState.Invalid && (data.CompareThresholdY(JointType.HandRight, JointType.Head, 0) == 1 || data.CompareThresholdY(JointType.HandLeft, JointType.Head, 0) == 1)) { _motionState = MotionState.Invalid; } // 当手放下时恢复初始状态 if (_motionState != MotionState.Initial) { if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1 || data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } } return false; }
private const double TimeMillisecondsThreshold = 1100d; // 时间阈值,以毫秒计算 #endregion Fields #region Methods protected override bool Recognise(FeatureData data) { // 上身的高度,用于近视计算手的比例 float maxHorizontalDistanceThreshold = 2 * data.ShoulderCenter2HipCenterHeight; switch (_motionState) { case MotionState.Initial: // 手超过了脊椎的位置 if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == 1 && data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == 1) { // 并且两手距离不远,用max因为向下的手势比较难识别,所以范围大 if (data.Hand2HandHorizontalDistance < maxHorizontalDistanceThreshold) { _dtBegin = DateTime.Now; // 获取开始时间 _motionState = MotionState.Valid; } else // 区别于双手收缩 { _motionState = MotionState.Invalid; } } break; case MotionState.Valid: // 判断是否低于一定的位置 if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1 && data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1) { _dtEnd = DateTime.Now; // 如果时间差小于一定的阈值则识别 if (_dtEnd.Subtract(_dtBegin).TotalMilliseconds < TimeMillisecondsThreshold) { // 当两手距离超过阈值后识别成功 if (data.Hand2HandHorizontalDistance > maxHorizontalDistanceThreshold*0.8) { _motionState = MotionState.Initial; // 识别后标记为初始状态 return true; } } else { _motionState = MotionState.Invalid; //时间到了后无效 } } else if (data.Hand2HandHorizontalDistance > maxHorizontalDistanceThreshold && data.CompareThresholdY(JointType.HandRight, JointType.ShoulderRight, 5) >= 0 && data.CompareThresholdY(JointType.HandLeft, JointType.ShoulderLeft, 5) >= 0) { _motionState = MotionState.Invalid; } //else if (data.CompareThresholdY(JointType.HandRight, JointType.HipRight, 14) == -1 || // 加入时间戳后需要重置 // data.CompareThresholdY(JointType.HandLeft, JointType.HipLeft, 14) == -1) //{ // _motionState = MotionState.Invalid; //} break; default: // 当手放下时恢复初始 if (data.CompareThresholdY(JointType.HandRight, JointType.Spine, 0) == -1 || data.CompareThresholdY(JointType.HandLeft, JointType.Spine, 0) == -1) { _motionState = MotionState.Initial; } break; } // 如果手抬起太高,则抬起失效 if (_motionState != MotionState.Invalid && (data.CompareThresholdY(JointType.HandRight, JointType.Head, 0) == 1 || data.CompareThresholdY(JointType.HandLeft, JointType.Head, 0) == 1)) { _motionState = MotionState.Invalid; } return false; }
/// <summary> /// 识别是否为当前的定义的动作 /// </summary> /// <param name="data">特征数据</param> /// <returns>识别是否成功</returns> protected abstract bool Recognise(FeatureData data);
/// <summary> /// 骨架信息生成了特征数据开始识别 /// </summary> /// <param name="data"></param> void _skeSubject_DataBinding(FeatureData data) { if (_direct!= "swust" && _walk != 0) //识别走 { if (DateTime.Now.Subtract(_dtBegin).TotalSeconds < TimeSecondsThreshold) { if (_walk >= 6) { _walk = 0; _timer.Start(); } } else { _walk = 0; } } try { // 动作进行识别 int rec = _motion.HandleDataEx(data); switch (rec) { case -1: return; //未识别直接返回 case 1: // 左脚走 if (_walk == 0) { ++_walk; _dtBegin = DateTime.Now; // 获取开始时间 leftFoot = true; } else if (leftFoot == false) { leftFoot = true; ++_walk; } break; case 2: // footrightup if (_walk == 0) { ++_walk; _dtBegin = DateTime.Now; // 获取开始时间 leftFoot = false; } else if (leftFoot == true) { leftFoot = false; ++_walk; } break; case 32: //左滑动 if (_direct == "swust") { _direct = "cq"; image_left.Visibility = Visibility.Hidden; image_right.Visibility = Visibility.Hidden; _timer.Start(); } break; case 33: // 右滑动 if (_direct == "swust") { _direct = "jy"; image_left.Visibility = Visibility.Hidden; image_right.Visibility = Visibility.Hidden; _timer.Start(); } break; case 20: // 变大 if (image_mask.Height*2 > this.Height) { return; } image_mask.Height *= 2; image_mask.Width *= 2; break; case 22: // 变小 if (image_mask.Height/2 < 120) { return; } image_mask.Height /= 2; image_mask.Width /= 2; break; case 30: // 左移动 _movingDict = -1; //if (image_mask.Margin.Left + _movingDict * image_mask.Width < -image_mask.Width) //{ // return; //} _timer2.Start(); break; case 31: _movingDict = 1; if (image_mask.Margin.Left + _movingDict * image_mask.Width > this.Width) { return; } _timer2.Start(); break; case 21: // 游泳 if (_direct == "cq" && _scene == 4) { _walk += 2; } break; default: break; } } catch (System.Exception ex) { MessageBox.Show(ex.Message); } }