Advertisement
Guest User

Untitled

a guest
Apr 19th, 2015
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.16 KB | None | 0 0
  1. //-----------------------------------------------------------------------
  2. // <copyright file="DtwGestureRecognizer.cs" company="Rhemyst and Rymix">
  3. // Open Source. Do with this as you will. Include this statement or
  4. // don't - whatever you like.
  5. //
  6. // No warranty or support given. No guarantees this will work or meet
  7. // your needs. Some elements of this project have been tailored to
  8. // the authors' needs and therefore don't necessarily follow best
  9. // practice. Subsequent releases of this project will (probably) not
  10. // be compatible with different versions, so whatever you do, don't
  11. // overwrite your implementation with any new releases of this
  12. // project!
  13. //
  14. // Enjoy working with Kinect!
  15. // </copyright>
  16. //-----------------------------------------------------------------------
  17.  
  18. using System.Diagnostics;
  19.  
  20. namespace FitnectApp
  21. {
  22. using System;
  23. using System.Collections;
  24.  
  25. internal class Fitnect
  26. {
  27. /// <summary>
  28. /// Size of obeservations vectors.
  29. /// </summary>
  30. private readonly int _dimension;
  31.  
  32. /// <summary>
  33. /// Maximum distance between the last observations of each sequence.
  34. /// </summary>
  35. private readonly double _firstThreshold;
  36.  
  37. /// <summary>
  38. /// Minimum length of a gesture before it can be recognised
  39. /// </summary>
  40. private readonly double _minimumLength;
  41.  
  42. /// <summary>
  43. /// Maximum DTW distance between an example and a sequence being classified.
  44. /// </summary>
  45. private readonly double _globalThreshold;
  46.  
  47. /// <summary>
  48. /// The gesture names. Index matches that of the sequences array in _sequences
  49. /// </summary>
  50. private readonly ArrayList _labels;
  51.  
  52. /// <summary>
  53. /// Maximum vertical or horizontal steps in a row.
  54. /// </summary>
  55. private readonly int _maxSlope;
  56.  
  57. /// <summary>
  58. /// The recorded gesture sequences
  59. /// </summary>
  60. private readonly ArrayList _sequences;
  61.  
  62. private int _currentMouvementId;
  63.  
  64. private int _ScorePositif;
  65.  
  66. private int _ScoreNegatif;
  67.  
  68. private int _lastMouvement;
  69.  
  70. /// <summary>
  71. /// Initializes a new instance of the DtwGestureRecognizer class
  72. /// First DTW constructor
  73. /// </summary>
  74. /// <param name="dim">Vector size</param>
  75. /// <param name="threshold">Maximum distance between the last observations of each sequence</param>
  76. /// <param name="firstThreshold">Minimum threshold</param>
  77. public Fitnect(int dim, double threshold, double firstThreshold, double minLen)
  78. {
  79. _dimension = dim;
  80. _sequences = new ArrayList();
  81. _labels = new ArrayList();
  82. _globalThreshold = threshold;
  83. _firstThreshold = firstThreshold;
  84. _maxSlope = int.MaxValue;
  85. _minimumLength = minLen;
  86. _ScoreNegatif = 0;
  87. _ScorePositif = 0;
  88. }
  89.  
  90. /// <summary>
  91. /// Initializes a new instance of the DtwGestureRecognizer class
  92. /// Second DTW constructor
  93. /// </summary>
  94. /// <param name="dim">Vector size</param>
  95. /// <param name="threshold">Maximum distance between the last observations of each sequence</param>
  96. /// <param name="firstThreshold">Minimum threshold</param>
  97. /// <param name="ms">Maximum vertical or horizontal steps in a row</param>
  98. public Fitnect(int dim, double threshold, double firstThreshold, int ms, double minLen)
  99. {
  100. _dimension = dim;
  101. _sequences = new ArrayList();
  102. _labels = new ArrayList();
  103. _globalThreshold = threshold;
  104. _firstThreshold = firstThreshold;
  105. _maxSlope = ms;
  106. _minimumLength = minLen;
  107. }
  108.  
  109. /// <summary>
  110. /// Add a seqence with a label to the known sequences library.
  111. /// The gesture MUST start on the first observation of the sequence and end on the last one.
  112. /// Sequences may have different lengths.
  113. /// </summary>
  114. /// <param name="seq">The sequence</param>
  115. /// <param name="lab">Sequence name</param>
  116. public void AddOrUpdate(ArrayList seq, string lab)
  117. {
  118. // First we check whether there is already a recording for this label. If so overwrite it, otherwise add a new entry
  119. int existingIndex = -1;
  120.  
  121. for (int i = 0; i < _labels.Count; i++)
  122. {
  123. if ((string)_labels[i] == lab)
  124. {
  125. existingIndex = i;
  126. }
  127. }
  128.  
  129. // If we have a match then remove the entries at the existing index to avoid duplicates. We will add the new entries later anyway
  130. if (existingIndex >= 0)
  131. {
  132. _sequences.RemoveAt(existingIndex);
  133. _labels.RemoveAt(existingIndex);
  134. }
  135.  
  136. // Add the new entries
  137. _sequences.Add(seq);
  138. _labels.Add(lab);
  139. }
  140.  
  141. /// <summary>
  142. /// Recognize gesture in the given sequence.
  143. /// It will always assume that the gesture ends on the last observation of that sequence.
  144. /// If the distance between the last observations of each sequence is too great, or if the overall DTW distance between the two sequence is too great, no gesture will be recognized.
  145. /// </summary>
  146. /// <param name="seq">The sequence to recognise</param>
  147. /// <returns>The recognised gesture name</returns>
  148. public string Recognize(ArrayList seq)
  149. {
  150. double minDist = double.PositiveInfinity;
  151. string classification = "__UNKNOWN";
  152. for (int i = 0; i < _sequences.Count; i++)
  153. {
  154. var example = (ArrayList)_sequences[i];
  155. ////Debug.WriteLine(Dist2((double[]) seq[seq.Count - 1], (double[]) example[example.Count - 1]));
  156. if (Dist2((double[])seq[seq.Count - 1], (double[])example[example.Count - 1]) < _firstThreshold)
  157. {
  158. double d = Dtw(seq, example) / example.Count;
  159. if (d < minDist)
  160. {
  161. minDist = d;
  162. classification = (string)_labels[i];
  163. if (_currentMouvementId == i)
  164. {
  165. nextMouvment();
  166. _ScorePositif++;
  167. }
  168.  
  169. else if (minDist < _globalThreshold)
  170. {
  171. _lastMouvement = i;
  172. _ScoreNegatif++;
  173. }
  174.  
  175. //else
  176. //{
  177. // _ScoreNegatif++;
  178. //}
  179.  
  180.  
  181. }
  182. }
  183. }
  184.  
  185. return (minDist < _globalThreshold ? classification : "__UNKNOWN") + " " /*+minDist.ToString()*/;
  186. }
  187.  
  188. /// <summary>
  189. /// Retrieves a text represeantation of the _label and its associated _sequence
  190. /// For use in dispaying debug information and for saving to file
  191. /// </summary>
  192. /// <returns>A string containing all recorded gestures and their names</returns>
  193. public string RetrieveText()
  194. {
  195. string retStr = String.Empty;
  196.  
  197. if (_sequences != null)
  198. {
  199. // Iterate through each gesture
  200. for (int gestureNum = 0; gestureNum < _sequences.Count; gestureNum++)
  201. {
  202. // Echo the label
  203. retStr += _labels[gestureNum] + "\r\n";
  204.  
  205. int frameNum = 0;
  206.  
  207. //Iterate through each frame of this gesture
  208. foreach (double[] frame in ((ArrayList)_sequences[gestureNum]))
  209. {
  210. // Extract each double
  211. foreach (double dub in (double[])frame)
  212. {
  213. retStr += dub + "\r\n";
  214. }
  215.  
  216. // Signifies end of this double
  217. retStr += "~\r\n";
  218.  
  219. frameNum++;
  220. }
  221.  
  222. // Signifies end of this gesture
  223. retStr += "----";
  224. if (gestureNum < _sequences.Count - 1)
  225. {
  226. retStr += "\r\n";
  227. }
  228. }
  229. }
  230.  
  231. return retStr;
  232. }
  233.  
  234. /// <summary>
  235. /// Compute the min DTW distance between seq2 and all possible endings of seq1.
  236. /// </summary>
  237. /// <param name="seq1">The first array of sequences to compare</param>
  238. /// <param name="seq2">The second array of sequences to compare</param>
  239. /// <returns>The best match</returns>
  240. public double Dtw(ArrayList seq1, ArrayList seq2)
  241. {
  242. // Init
  243. var seq1R = new ArrayList(seq1);
  244. seq1R.Reverse();
  245. var seq2R = new ArrayList(seq2);
  246. seq2R.Reverse();
  247. var tab = new double[seq1R.Count + 1, seq2R.Count + 1];
  248. var slopeI = new int[seq1R.Count + 1, seq2R.Count + 1];
  249. var slopeJ = new int[seq1R.Count + 1, seq2R.Count + 1];
  250.  
  251. for (int i = 0; i < seq1R.Count + 1; i++)
  252. {
  253. for (int j = 0; j < seq2R.Count + 1; j++)
  254. {
  255. tab[i, j] = double.PositiveInfinity;
  256. slopeI[i, j] = 0;
  257. slopeJ[i, j] = 0;
  258. }
  259. }
  260.  
  261. tab[0, 0] = 0;
  262.  
  263. // Dynamic computation of the DTW matrix.
  264. for (int i = 1; i < seq1R.Count + 1; i++)
  265. {
  266. for (int j = 1; j < seq2R.Count + 1; j++)
  267. {
  268. if (tab[i, j - 1] < tab[i - 1, j - 1] && tab[i, j - 1] < tab[i - 1, j] &&
  269. slopeI[i, j - 1] < _maxSlope)
  270. {
  271. tab[i, j] = Dist2((double[])seq1R[i - 1], (double[])seq2R[j - 1]) + tab[i, j - 1];
  272. slopeI[i, j] = slopeJ[i, j - 1] + 1;
  273. slopeJ[i, j] = 0;
  274. }
  275. else if (tab[i - 1, j] < tab[i - 1, j - 1] && tab[i - 1, j] < tab[i, j - 1] &&
  276. slopeJ[i - 1, j] < _maxSlope)
  277. {
  278. tab[i, j] = Dist2((double[])seq1R[i - 1], (double[])seq2R[j - 1]) + tab[i - 1, j];
  279. slopeI[i, j] = 0;
  280. slopeJ[i, j] = slopeJ[i - 1, j] + 1;
  281. }
  282. else
  283. {
  284. tab[i, j] = Dist2((double[])seq1R[i - 1], (double[])seq2R[j - 1]) + tab[i - 1, j - 1];
  285. slopeI[i, j] = 0;
  286. slopeJ[i, j] = 0;
  287. }
  288. }
  289. }
  290.  
  291. // Find best between seq2 and an ending (postfix) of seq1.
  292. double bestMatch = double.PositiveInfinity;
  293. for (int i = 1; i < (seq1R.Count + 1) - _minimumLength; i++)
  294. {
  295. if (tab[i, seq2R.Count] < bestMatch)
  296. {
  297. bestMatch = tab[i, seq2R.Count];
  298. }
  299. }
  300.  
  301. return bestMatch;
  302. }
  303.  
  304. /// <summary>
  305. /// Computes a 1-distance between two observations. (aka Manhattan distance).
  306. /// </summary>
  307. /// <param name="a">Point a (double)</param>
  308. /// <param name="b">Point b (double)</param>
  309. /// <returns>Manhattan distance between the two points</returns>
  310. private double Dist1(double[] a, double[] b)
  311. {
  312. double d = 0;
  313. for (int i = 0; i < _dimension; i++)
  314. {
  315. d += Math.Abs(a[i] - b[i]);
  316. }
  317.  
  318. return d;
  319. }
  320.  
  321. /// <summary>
  322. /// Computes a 2-distance between two observations. (aka Euclidian distance).
  323. /// </summary>
  324. /// <param name="a">Point a (double)</param>
  325. /// <param name="b">Point b (double)</param>
  326. /// <returns>Euclidian distance between the two points</returns>
  327. private double Dist2(double[] a, double[] b)
  328. {
  329. double d = 0;
  330. for (int i = 0; i < _dimension; i++)
  331. {
  332. d += Math.Pow(a[i] - b[i], 2);
  333. }
  334.  
  335. return Math.Sqrt(d);
  336. }
  337.  
  338. private void nextMouvment()
  339. {
  340. _currentMouvementId++;
  341. _currentMouvementId = _currentMouvementId % _labels.Count;
  342. }
  343.  
  344.  
  345. public string getCurrentMouvement()
  346. {
  347. return (string)_labels[_currentMouvementId];
  348. }
  349.  
  350. public string getScorePositif()
  351. {
  352. return "" + _ScorePositif;
  353. }
  354.  
  355. public string getScoreNegatif()
  356. {
  357. return "" + _ScoreNegatif;
  358. }
  359.  
  360. }
  361. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement