--- /dev/null
+using System.Collections.Generic;
+using System.Numerics;
+using Tizen.Multimedia;
+
+namespace Fitness.Services
+{
+ /// <summary>
+ /// SquatDetector
+ /// </summary>
+ public static class SquatDetector
+ {
+ // SquatLowerBody is calculation result of squat picture from
+ // https://review.tizen.org/gerrit/gitweb?p=test/tct/native/api.git;a=blob;f=src/utc/capi-media-vision/res/inference/images/poseLandmark.jpg;h=4bead08b8dc3687f228b5ab885e7136b26331cfb;hb=refs/heads/tizen
+ // Each below vector is derived from two points respectively,
+ // 0. RightUpLeg => RightLowLeg,
+ // 1. RightLowLeg => RightFoot,
+ // 2. LeftUpLeg => LeftLowLeg,
+ // 4. LeftLowLeg => LeftFoot
+ private static readonly List<Vector2> SquatLowerBody = new List<Vector2>(new[]
+ {
+ new Vector2(0.6666667F, -0.33333334F),
+ new Vector2(0F, -1F),
+ new Vector2(-0.6666667F, -0.33333334F),
+ new Vector2(0F, -1F),
+ });
+
+ /// <summary>
+ /// Return Average of lower body <see href="https://en.wikipedia.org/wiki/Cosine_similarity">Cosine Similarity</see> between input user pose and ground truth pose
+ /// </summary>
+ /// <param name="userBody">user body detection result</param>
+ /// <returns>Float score value. (-1.0 ~ 1.0)</returns>
+ public static float Similarity(List<Point> userBody)
+ {
+ if (userBody.Count != System.Enum.GetNames(typeof(PoseDetector.BodyPart)).Length)
+ {
+ throw new System.ArgumentException("Must have all points which represent user body", "userBody");
+ }
+
+ List<Vector2> userSquat = new List<Vector2>(new[]
+ {
+ L1UnitVectorize(userBody[(int)PoseDetector.BodyPart.RightUpLeg], userBody[(int)PoseDetector.BodyPart.RightLowLeg]),
+ L1UnitVectorize(userBody[(int)PoseDetector.BodyPart.RightLowLeg], userBody[(int)PoseDetector.BodyPart.RightFoot]),
+ L1UnitVectorize(userBody[(int)PoseDetector.BodyPart.LeftUpLeg], userBody[(int)PoseDetector.BodyPart.LeftLowLeg]),
+ L1UnitVectorize(userBody[(int)PoseDetector.BodyPart.LeftLowLeg], userBody[(int)PoseDetector.BodyPart.LeftFoot]),
+ });
+
+ float score = 0F;
+
+ for (int i = 0; i < SquatLowerBody.Count; i++)
+ {
+ score += Vector2.Dot(SquatLowerBody[i], userSquat[i]) / SquatLowerBody[i].Length() / userSquat[i].Length();
+ }
+
+ return score / SquatLowerBody.Count;
+ }
+
+ private static Vector2 L1UnitVectorize(Point from, Point to)
+ {
+ int vx = from.X - to.X;
+ int vy = from.Y - to.Y;
+ float parent = System.Math.Abs(vx) + System.Math.Abs(vy);
+ return new Vector2(vx / parent, vy / parent);
+ }
+ }
+}