PositionCalculator.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. using Assets.StreetLight.Interfaces;
  2. using Assets.StreetLight.Poco;
  3. using MathNet.Numerics.LinearAlgebra;
  4. using MathNet.Numerics.LinearAlgebra.Double;
  5. using System;
  6. using System.Collections.Generic;
  7. using UnityEngine;
  8. namespace Assets.StreetLight.Scripts
  9. {
  10. public class PositionCalculator
  11. {
  12. private List<CalibrationPoint> calibrationVectors;
  13. private Matrix<double> homography;
  14. public PositionCalculator(List<CalibrationPoint> calibrationVectors)
  15. {
  16. this.calibrationVectors = calibrationVectors;
  17. CalculateHomographySimple();
  18. }
  19. private void CalculateHomographySVD()
  20. {
  21. if (!(calibrationVectors?.Count >= 4))
  22. {
  23. throw new InvalidOperationException("Must have at least 4 correspondences to calculate a homography.");
  24. }
  25. }
  26. private void CalculateHomographyRansac()
  27. {
  28. if (!(calibrationVectors?.Count >= 4))
  29. {
  30. throw new InvalidOperationException("Must have at least 4 correspondences to calculate a homography.");
  31. }
  32. // TODO: RANSAC with conditioning
  33. var inlierThreshold = 5.0;
  34. var inlierProbability = 0.25;
  35. var samplesPerInteration = 4;
  36. var confidence = 0.99;
  37. throw new NotImplementedException();
  38. }
  39. private void CalculateHomographySimple()
  40. {
  41. if (!(calibrationVectors?.Count >= 4))
  42. {
  43. throw new InvalidOperationException("Must have at least 4 correspondences to calculate a homography.");
  44. }
  45. var cv = calibrationVectors;
  46. Matrix<double> matrixA = DenseMatrix.OfArray(new double[,]
  47. {
  48. {cv[0].WorldPosition.x, cv[0].WorldPosition.z, 1, 0, 0, 0, -cv[0].UnityPosition.x*cv[0].WorldPosition.x, -cv[0].UnityPosition.x*cv[0].WorldPosition.z},
  49. {0, 0, 0, cv[0].WorldPosition.x, cv[0].WorldPosition.z, 1, -cv[0].UnityPosition.z*cv[0].WorldPosition.x, -cv[0].UnityPosition.z*cv[0].WorldPosition.z},
  50. {cv[1].WorldPosition.x, cv[1].WorldPosition.z, 1, 0, 0, 0, -cv[1].UnityPosition.x*cv[1].WorldPosition.x, -cv[1].UnityPosition.x*cv[1].WorldPosition.z},
  51. {0, 0, 0, cv[1].WorldPosition.x, cv[1].WorldPosition.z, 1, -cv[1].UnityPosition.z*cv[1].WorldPosition.x, -cv[1].UnityPosition.z*cv[1].WorldPosition.z},
  52. {cv[2].WorldPosition.x, cv[2].WorldPosition.z, 1, 0, 0, 0, -cv[2].UnityPosition.x*cv[2].WorldPosition.x, -cv[2].UnityPosition.x*cv[2].WorldPosition.z},
  53. {0, 0, 0, cv[2].WorldPosition.x, cv[2].WorldPosition.z, 1, -cv[2].UnityPosition.z*cv[2].WorldPosition.x, -cv[2].UnityPosition.z*cv[2].WorldPosition.z},
  54. {cv[3].WorldPosition.x, cv[3].WorldPosition.z, 1, 0, 0, 0, -cv[3].UnityPosition.x*cv[3].WorldPosition.x, -cv[3].UnityPosition.x*cv[3].WorldPosition.z},
  55. {0, 0, 0, cv[3].WorldPosition.x, cv[3].WorldPosition.z, 1, -cv[3].UnityPosition.z*cv[3].WorldPosition.x, -cv[3].UnityPosition.z*cv[3].WorldPosition.z}
  56. });
  57. Matrix<double> matrixB = DenseMatrix.OfArray(new double[,]
  58. {
  59. {cv[0].UnityPosition.x},
  60. {cv[0].UnityPosition.z},
  61. {cv[1].UnityPosition.x},
  62. {cv[1].UnityPosition.z},
  63. {cv[2].UnityPosition.x},
  64. {cv[2].UnityPosition.z},
  65. {cv[3].UnityPosition.x},
  66. {cv[3].UnityPosition.z}
  67. });
  68. var lambda = (matrixA.Transpose() * matrixA).Inverse() * matrixA.Transpose() * matrixB;
  69. homography = DenseMatrix.OfArray(new double[,]
  70. {
  71. { lambda[0,0], lambda[1,0], lambda[2,0]},
  72. { lambda[3,0], lambda[4,0], lambda[5,0]},
  73. { lambda[6,0], lambda[7,0], 1}
  74. });
  75. testCalibration();
  76. }
  77. public Vector3 CalculateUnityPosition(Person person)
  78. {
  79. return WorldPositionToUnityPosition(person.WorldPosition);
  80. }
  81. private Vector3 WorldPositionToUnityPosition(Vector3 worldPosition)
  82. {
  83. var vector = DenseVector.OfArray(new double[] { worldPosition.x, worldPosition.z, 1 });
  84. var output = homography * vector;
  85. var scaledOutput = output / output[2];
  86. var resultVector = new Vector3((float)scaledOutput[0], 0, (float)scaledOutput[1]);
  87. return resultVector;
  88. }
  89. /// <summary>
  90. /// For internal debugging only.
  91. /// </summary>
  92. private void testCalibration()
  93. {
  94. foreach (var c in calibrationVectors)
  95. {
  96. var test = DenseVector.OfArray(new double[] { c.WorldPosition.x, c.WorldPosition.z, 1 });
  97. var testOutput = homography * test;
  98. var scaledTestOutput = testOutput / testOutput[2];
  99. }
  100. }
  101. }
  102. }