|
@@ -1,106 +1,20 @@
|
|
-using Assets.StreetLight.Interfaces;
|
|
|
|
-using Assets.StreetLight.Poco;
|
|
|
|
|
|
+using Assets.StreetLight.Poco;
|
|
using MathNet.Numerics.LinearAlgebra;
|
|
using MathNet.Numerics.LinearAlgebra;
|
|
using MathNet.Numerics.LinearAlgebra.Double;
|
|
using MathNet.Numerics.LinearAlgebra.Double;
|
|
-using MathNet.Numerics.Statistics;
|
|
|
|
-using Newtonsoft.Json;
|
|
|
|
-using System;
|
|
|
|
-using System.Collections.Generic;
|
|
|
|
-using System.Globalization;
|
|
|
|
-using System.IO;
|
|
|
|
-using System.Linq;
|
|
|
|
-using System.Security.Cryptography;
|
|
|
|
-using System.Threading;
|
|
|
|
using UnityEngine;
|
|
using UnityEngine;
|
|
-using Random = System.Random;
|
|
|
|
|
|
|
|
namespace Assets.StreetLight.Scripts
|
|
namespace Assets.StreetLight.Scripts
|
|
{
|
|
{
|
|
public class PositionCalculator
|
|
public class PositionCalculator
|
|
{
|
|
{
|
|
- private readonly List<CalibrationPoint> calibrationVectors;
|
|
|
|
- private Matrix<double> homography;
|
|
|
|
|
|
+ private readonly Matrix<double> homography;
|
|
|
|
|
|
- public PositionCalculator(List<CalibrationPoint> calibrationVectors)
|
|
|
|
|
|
+ public PositionCalculator(double[,] homographyArray)
|
|
{
|
|
{
|
|
- this.calibrationVectors = calibrationVectors;
|
|
|
|
-
|
|
|
|
- CalculateHomographyRansac();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Uses RANSAC and an SVD to calculate the homography from many calibration points.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <exception cref="InvalidOperationException"></exception>
|
|
|
|
- /// <remarks>Heavily based on the formulas and algorithms discussed in Computer Vision I by Stefan Roth</remarks>
|
|
|
|
- private void CalculateHomographyRansac()
|
|
|
|
- {
|
|
|
|
- if (!(calibrationVectors?.Count >= 4))
|
|
|
|
- {
|
|
|
|
- throw new InvalidOperationException("Must have at least 4 correspondences to calculate a homography.");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var lines = calibrationVectors.Select(v => $"{v.WorldPosition.x.ToString("0." + new string('#', 50), CultureInfo.InvariantCulture)} {v.WorldPosition.z.ToString("0." + new string('#', 50), CultureInfo.InvariantCulture)} {v.UnityPosition.x.ToString("0." + new string('#', 50), CultureInfo.InvariantCulture)} {v.UnityPosition.z.ToString("0." + new string('#', 50), CultureInfo.InvariantCulture)}");
|
|
|
|
-
|
|
|
|
- var pairsString = string.Join(Environment.NewLine, lines);
|
|
|
|
-
|
|
|
|
- File.WriteAllText(@"C:\Git\git.tk.informatik.tu-darmstadt.de\StreetLight\Assets\StreamingAssets\pairs.csv", pairsString);
|
|
|
|
- var homographyString = File.ReadAllLines(@"C:\Git\git.tk.informatik.tu-darmstadt.de\StreetLight\Assets\StreamingAssets\homography.csv");
|
|
|
|
-
|
|
|
|
- var values = homographyString.Select(l => l.Split(' ').Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray()).ToArray();
|
|
|
|
-
|
|
|
|
- double[,] array = new double[3, 3];
|
|
|
|
-
|
|
|
|
- for (int i = 0; i < 3; i++)
|
|
|
|
- {
|
|
|
|
- for (int j = 0; j < 3; j++)
|
|
|
|
- {
|
|
|
|
- array[i, j] = values[i][j];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- homography = DenseMatrix.OfArray(array);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private (Matrix<double>, Matrix<double>) ComputeHomography(ICollection<(Vector<double>, Vector<double>)> conditionedCorrespondences, Matrix<double> t1, Matrix<double> t2)
|
|
|
|
- {
|
|
|
|
- var numberOfCorrespondences = conditionedCorrespondences.Count;
|
|
|
|
-
|
|
|
|
- var A = new List<double[]>();
|
|
|
|
-
|
|
|
|
- foreach (var correspondence in conditionedCorrespondences)
|
|
|
|
- {
|
|
|
|
- var point1 = correspondence.Item1 / correspondence.Item1[2];
|
|
|
|
- var point2 = correspondence.Item2 / correspondence.Item2[2];
|
|
|
|
- A.Add(new double[] { 0, 0, 0, point1[0], point1[1], point1[2], -point2[1] * point1[0], -point2[1] * point1[1], -point2[1] * point1[2] });
|
|
|
|
- A.Add(new double[] { -point1[0], -point1[1], -point1[2], 0, 0, 0, point2[0] * point1[0], point2[0] * point1[1], point2[0] * point1[2] });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var matrix = DenseMatrix.OfRowArrays(A);
|
|
|
|
- var svd = matrix.Svd(true);
|
|
|
|
- var h = svd.VT.EnumerateRows().Last();
|
|
|
|
- var HC = DenseMatrix.OfArray(new[,]
|
|
|
|
- {
|
|
|
|
- { h[0], h[1], h[2] },
|
|
|
|
- { h[3], h[4], h[5] },
|
|
|
|
- { h[6], h[7], h[8] }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- var normalizedHC = HC / HC[2, 2];
|
|
|
|
-
|
|
|
|
- var H = t2.Inverse() * (normalizedHC * t1);
|
|
|
|
-
|
|
|
|
- var normalizedH = H / H[2, 2];
|
|
|
|
-
|
|
|
|
- return (normalizedH, normalizedHC);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public Vector3 CalculateUnityPosition(Person person)
|
|
|
|
- {
|
|
|
|
- return WorldPositionToUnityPosition(person.WorldPosition);
|
|
|
|
|
|
+ homography = DenseMatrix.OfArray(homographyArray);
|
|
}
|
|
}
|
|
|
|
|
|
- private Vector3 WorldPositionToUnityPosition(Vector3 worldPosition)
|
|
|
|
|
|
+ public Vector3 WorldPositionToUnityPosition(Vector3 worldPosition)
|
|
{
|
|
{
|
|
var homogeneousWorldPosition = DenseVector.OfArray(new double[] { worldPosition.x, worldPosition.z, 1 });
|
|
var homogeneousWorldPosition = DenseVector.OfArray(new double[] { worldPosition.x, worldPosition.z, 1 });
|
|
|
|
|