/// <summary>
        /// Bodyの関節を反転する
        /// </summary>
        public void InverseJoints()
        {
            Dictionary <JointType, Joint> newJoints      = new Dictionary <JointType, Joint>();
            Dictionary <JointType, Point> newColorPoints = new Dictionary <JointType, Point>();
            Dictionary <JointType, Point> newDepthPoints = new Dictionary <JointType, Point>();

            foreach (JointType key in Enum.GetValues(typeof(JointType)))
            {
                JointType newKey = CalcEx.GetMirroredJoint(key);
                if (this.Joints.ContainsKey(key))
                {
                    newJoints[newKey] = this.Joints[key];
                }
                if (this.colorSpacePoints.ContainsKey(key))
                {
                    newColorPoints[newKey] = this.colorSpacePoints[key];
                }
                if (this.depthSpacePoints.ContainsKey(key))
                {
                    newDepthPoints[newKey] = this.depthSpacePoints[key];
                }
            }
            this.Joints           = newJoints;
            this.colorSpacePoints = newColorPoints;
            this.depthSpacePoints = newDepthPoints;
        }
        /// <summary>
        /// Jointから絶対座標を引くDictionary二つの間の距離を求めます
        /// </summary>
        /// <param name="jointWithAbsPosition1">骨格ごとの絶対座標1</param>
        /// <param name="jointWithAbsPosition2">骨格ごとの絶対座標2</param>
        /// <param name="mirrored">一方の骨格を左右反転した結果で距離を求めるかどうか</param>
        /// <returns></returns>
        static double getDistance(IDictionary <JointType, CvPoint3D64f> jointWithAbsPosition1, IDictionary <JointType, CvPoint3D64f> jointWithAbsPosition2, bool mirrored)
        {
            IEnumerable <JointType> joints2Alt     = jointWithAbsPosition2.Keys.Select(j => mirrored ? CalcEx.GetMirroredJoint(j) : j);
            List <JointType>        intersect      = jointWithAbsPosition1.Keys.Intersect(joints2Alt).ToList();
            List <double>           distanceSqList = new List <double>();

            foreach (JointType joint in intersect)
            {
                JointType jointAlt = mirrored ? CalcEx.GetMirroredJoint(joint) : joint;
                distanceSqList.Add(CvEx.GetDistanceSq(jointWithAbsPosition1[joint], jointWithAbsPosition2[jointAlt]));
            }
            // 中央値の平方根
            return(Math.Sqrt(CalcEx.GetMedian(distanceSqList)));
        }
예제 #3
0
        /// <summary>
        /// 反転しているJointsをPivot基準に修正する
        /// </summary>
        /// <param name="joints"></param>
        /// <param name="conversion"></param>
        /// <returns></returns>
        public Dictionary <JointType, Joint> CorrectMirrorJoint(Dictionary <JointType, Joint> joints, CvMat conversion)
        {
            HashSet <JointType> mirroredPivotKeys                  = new HashSet <JointType>(pivot.Keys.Select(j => CalcEx.GetMirroredJoint(j)));
            List <JointType>    availableKeys                      = pivot.Keys.Where(j => mirroredPivotKeys.Contains(j)).ToList(); // pivotの左右反転して共通なキー
            Dictionary <JointType, CvPoint3D64f> absJoints         = joints.ToDictionary(p => p.Key, p => CvEx.ConvertPoint3D(p.Value.Position.ToCvPoint3D(), conversion));
            Dictionary <JointType, CvPoint3D64f> absMirroredJoints = absJoints.ToDictionary(p => CalcEx.GetMirroredJoint(p.Key), p => p.Value);
            List <JointType> keysNormal   = availableKeys.Intersect(absJoints.Keys).ToList();
            List <JointType> keysMirrored = availableKeys.Intersect(absMirroredJoints.Keys).ToList();

            if (keysNormal.Count > 0 && keysMirrored.Count > 0)
            {
                double avg1 = keysNormal.Select(j => CvEx.GetDistanceSq(pivot[j], absJoints[j])).Average();
                double avg2 = keysMirrored.Select(j => CvEx.GetDistanceSq(pivot[j], absMirroredJoints[j])).Average();
                // mirroredのほうが似てる場合
                if (avg2 < avg1)
                {
                    return(joints.ToDictionary(p => CalcEx.GetMirroredJoint(p.Key), p => p.Value));
                }
            }
            return(joints);
        }
        /// <summary>
        /// 修正してくれるやつ
        /// </summary>
        /// <param name="frameSeq"></param>
        public static void Correct(FrameSequence frameSeq)
        {
            List <OrderTuple> orders = new List <OrderTuple>();

            foreach (var pair in frameSeq.Frames.Select((frame, index) => Tuple.Create(frame, index)))
            {
                for (int recordNo = 0; recordNo < pair.Item1.recordNum; recordNo++)
                {
                    orders.Add(new OrderTuple(pair.Item1.Time, recordNo, pair.Item2));
                }
            }
            // 前フレームのユーザと対応するBodyを保持する
            Dictionary <int, SerializableBody>[] prevUserBodyMapArray = new Dictionary <int, SerializableBody> [frameSeq.recordNum];
            for (int i = 0; i < frameSeq.recordNum; i++)
            {
                prevUserBodyMapArray[i] = new Dictionary <int, SerializableBody>();
            }
            SerializableBody prevUserBody;

            orders = orders.OrderBy(x => x.Timestamp.Ticks).ToList();
            SkeletonInterpolator interp = new SkeletonInterpolator(0.5, true);

            foreach (OrderTuple tuple in orders)
            {
                Frame             currFrame   = frameSeq.Frames[tuple.FrameIndex];
                const long        maxInterval = (long)(10000000 * 0.1);
                DateTime          prev        = new DateTime(tuple.Timestamp.Ticks - maxInterval);
                IEnumerable <int> users       = currFrame.GetBodyList(tuple.RecordIndex).Select(b => b.integratedId);
                foreach (int user in users)
                {
                    SerializableBody currBody = currFrame.GetSelectedBody(tuple.RecordIndex, integratedId: user);
                    // 前のBodyと比較して同じ場合は処理をスキップする
                    if (prevUserBodyMapArray[tuple.RecordIndex].TryGetValue(user, out prevUserBody) && prevUserBody.Joints != null && currBody.Joints != null)
                    {
                        double avgDistanceSq = CalcBodyDistanceSq(prevUserBody.Joints, currBody.Joints).Values.Average();
                        if (avgDistanceSq == 0.0)
                        {
                            //currFrame.DeleteBody(tuple.RecordIndex, integratedId: user);
                            continue;
                        }
                    }
                    prevUserBodyMapArray[tuple.RecordIndex][user] = currBody;

                    Dictionary <JointType, CvPoint3D64f> prevJoints = interp.IntegrateSkeleton(prev, user, frameSeq);
                    if (prevJoints != null && currBody.Joints != null)
                    {
                        Dictionary <JointType, CvPoint3D64f> currJoints = currBody.Joints.ToDictionary(p => p.Key, p => (CvPoint3D64f)p.Value.Position.ToCvPoint3D());
                        HashSet <JointType> mirroredPrevKeys            = new HashSet <JointType>(prevJoints.Keys.Select(j => CalcEx.GetMirroredJoint(j)));
                        if (currJoints != null && prevJoints != null)
                        {
                            var absJoints         = currJoints.ToDictionary(p => p.Key, p => CvEx.ConvertPoint3D(p.Value, frameSeq.ToWorldConversions[tuple.RecordIndex]));
                            var absMirroredJoints = absJoints.ToDictionary(p => CalcEx.GetMirroredJoint(p.Key), p => p.Value);
                            var availableKeys     = prevJoints.Keys.Where(j => mirroredPrevKeys.Contains(j)).ToList();
                            var keysNormal        = availableKeys.Intersect(absJoints.Keys).ToList();
                            var keysMirrored      = availableKeys.Intersect(absMirroredJoints.Keys).ToList();

                            if (keysNormal.Count > 0 && keysMirrored.Count > 0)
                            {
                                double avg1 = keysNormal.Select(j => CvEx.GetDistanceSq(prevJoints[j], absJoints[j])).Average();
                                double avg2 = keysMirrored.Select(j => CvEx.GetDistanceSq(prevJoints[j], absMirroredJoints[j])).Average();
                                if (avg2 < avg1)
                                {
                                    currFrame.InverseBody(tuple.RecordIndex, integratedId: user);
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 統合後のデータに対して瞬間的な左右反転をなおす
        /// </summary>
        /// <param name="seqJoints"></param>
        public static List <Dictionary <JointType, CvPoint3D64f> > SequentialCorrect(List <Dictionary <JointType, CvPoint3D64f> > seqJoints)
        {
            CvPoint3D64f prevShoulderVector = new CvPoint3D64f();
            CvPoint3D64f prevHipVector      = new CvPoint3D64f();
            List <Dictionary <JointType, CvPoint3D64f> > res = new List <Dictionary <JointType, CvPoint3D64f> >();

            foreach (Dictionary <JointType, CvPoint3D64f> joints in seqJoints)
            {
                bool reverse = false;
                if (joints.ContainsKey(JointType.ShoulderLeft) && joints.ContainsKey(JointType.ShoulderRight))
                {
                    CvPoint3D64f shoulderVector = joints[JointType.ShoulderLeft] - joints[JointType.ShoulderRight];
                    if (prevShoulderVector == default(CvPoint3D64f))
                    {
                        prevShoulderVector = shoulderVector;
                    }
                    if (CvEx.Cos(shoulderVector, prevShoulderVector) <= -0.8)
                    {
                        reverse = true;
                    }
                }
                if (joints.ContainsKey(JointType.HipLeft) && joints.ContainsKey(JointType.HipRight))
                {
                    CvPoint3D64f hipVector = joints[JointType.HipLeft] - joints[JointType.HipRight];
                    if (prevHipVector == default(CvPoint3D64f))
                    {
                        prevHipVector = hipVector;
                    }
                    if (CvEx.Cos(hipVector, prevHipVector) <= -0.8)
                    {
                        reverse = true;
                    }
                }

                if (reverse)
                {
                    Dictionary <JointType, CvPoint3D64f> newJoints = joints.ToDictionary(p => CalcEx.GetMirroredJoint(p.Key), p => p.Value);
                    res.Add(newJoints);
                    // reverseした後のただしいベクトルを入れなおしておく
                    if (joints.ContainsKey(JointType.ShoulderLeft) && joints.ContainsKey(JointType.ShoulderRight))
                    {
                        prevShoulderVector = newJoints[JointType.ShoulderLeft] - newJoints[JointType.ShoulderRight];
                    }
                    if (joints.ContainsKey(JointType.HipLeft) && joints.ContainsKey(JointType.HipRight))
                    {
                        prevHipVector = newJoints[JointType.HipLeft] - newJoints[JointType.HipRight];
                    }
                }
                else
                {
                    res.Add(joints);
                }
            }
            return(res);
        }