public MatchVisualization(MatchVisualization other) { raysUpSpace = other.raysUpSpace.ToList(); poseOfUpSpace = other.poseOfUpSpace; projectedRays = other.projectedRays.ToList(); markersIndices = other.markersIndices.ToList(); }
Bool IEnvironment.match(Vector3[] Rays, out MarkerIndex[] Markers, out Pose PositionofUp) { const float projectionsMatchTolerance = 0.06f; Markers = Enumerable.Repeat(MarkerIndex.Unknown, Rays.Length).ToArray(); PositionofUp = new Pose(); if (Rays.Length != 3) { return(false); } var projecties = projectRaysOnFloor(Rays); var M = new float[6, 4]; var b = new float[6]; for (int i = 0; i < 3; ++i) { M[2 * i, 0] = projecties[i].x; M[2 * i, 1] = -projecties[i].y; M[2 * i, 2] = 1; M[2 * i + 1, 0] = projecties[i].y; M[2 * i + 1, 1] = projecties[i].x; M[2 * i + 1, 3] = 1; b[2 * i] = _markers[i].x; b[2 * i + 1] = _markers[i].y; } var invM = M.transpose().multiply(M).inverse().multiply(M.transpose()); int BestMatch = -1; float bestError = float.MaxValue; var bestTransform2d = new ConvertTo2D(); for (int idPermutation = 0; idPermutation < 6; ++idPermutation) { var curB = new float[6]; for (int i = 0; i < 4; ++i) { int j = permutations[idPermutation][i]; curB[2 * i] = b[2 * j]; curB[2 * i + 1] = b[2 * j + 1]; } var transformParams = invM.multiply(curB); var transform2d = new ConvertTo2D(transformParams[0], transformParams[1], transformParams[2], transformParams[3]); float error = 0; for (int idMarker = 0; idMarker < 3; ++idMarker) { error += (transform2d.apply(projecties[idMarker]) - _markers[permutations[idPermutation][idMarker]]).sqrMagnitude; } if (error < bestError) { bestError = error; BestMatch = idPermutation; bestTransform2d = transform2d; } } if (bestError > projectionsMatchTolerance) { return(false); } for (int i = 0; i < Rays.Length; ++i) { Markers[i].value = (uint)permutations[BestMatch][i]; } var position = new Vector3(bestTransform2d.Translate.x, bestTransform2d.Scale, bestTransform2d.Translate.y); var rotation = Quaternion.AxisAngle(Vector3.up, -bestTransform2d.Angle); PositionofUp = new Pose(position, rotation); lock (_visobject) { _matchViz = new MatchVisualization( Rays.ToList(), PositionofUp, projecties.Select(p => bestTransform2d.apply(p)).ToList(), Markers); } return(true); }
Bool IEnvironment.match(Vector3[] raysUpSpace, out MarkerIndex[] markersIndices, out Pose poseOfUpSpace) { const float projectionsMatchTolerance = 0.05f; markersIndices = Enumerable.Repeat(MarkerIndex.Unknown, raysUpSpace.Length).ToArray(); poseOfUpSpace = new Pose(); // For the sake of simplicity, we won't deal with cases when more than three rays is visible. if (raysUpSpace.Length != 3) { return(false); } // rays projection on X-Y plane of "up space" at height of 1 meter var projections = projectRaysOnFloor(raysUpSpace); // We have to find transform that match rays projections to markers in world space in form f(x) = SR*x + t, where // SR - scale and rotation matrix: s*{{cos(r), -sin(r)}, {sin(r), cos(r)}}; s - scale coefficient, r - rotation angle, // t - translation vector. // Lets solve system of linear equations {SR*ai + t = bi} for SR and t // System can be rewritten as M*x = b // / a0.x -a0.y 1 0 \ / s*cos(r) \ / b0.x \ // | a0.y a0.x 0 1 | * | s*sin(r) | = | b0.y | // | ... | | t.x | | ... | // \ ... / \ t.y / \ ... / var M = new float[6, 4]; var b = new float[6]; for (int i = 0; i < 3; ++i) { M[2 * i, 0] = projections[i].x; M[2 * i, 1] = -projections[i].y; M[2 * i, 2] = 1; M[2 * i + 1, 0] = projections[i].y; M[2 * i + 1, 1] = projections[i].x; M[2 * i + 1, 3] = 1; b[2 * i] = _markers[i].x; b[2 * i + 1] = _markers[i].y; } // left inverse var invM = M.transpose().multiply(M).inverse().multiply(M.transpose()); // Iterate over all possible permutations and pick the best one if its good enough. int bestPermutationId = -1; float bestError = float.MaxValue; var bestTransform2d = new Transform2d(); for (int idPermutation = 0; idPermutation < 6; ++idPermutation) { // make vector of constant terms for current markers order var curB = new float[6]; for (int i = 0; i < 3; ++i) { int j = permutations[idPermutation][i]; curB[2 * i] = b[2 * j]; curB[2 * i + 1] = b[2 * j + 1]; } var transformParams = invM.multiply(curB); // {scale*cos(r), scale*sin(r), t.x, t.y} var transform2d = new Transform2d(transformParams[0], transformParams[1], transformParams[2], transformParams[3]); float error = 0; // sum of square distances between corresponding markers and transformed rays projections for (int idMarker = 0; idMarker < 3; ++idMarker) { error += (transform2d.apply(projections[idMarker]) - _markers[permutations[idPermutation][idMarker]]).sqrMagnitude; } if (error < bestError) { bestError = error; bestPermutationId = idPermutation; bestTransform2d = transform2d; } } if (bestError > projectionsMatchTolerance) { return(false); } for (int i = 0; i < raysUpSpace.Length; ++i) { markersIndices[i].value = (uint)permutations[bestPermutationId][i]; } var position = new Vector3(bestTransform2d.Translate.x, bestTransform2d.Scale, bestTransform2d.Translate.y); var rotation = Quaternion.AxisAngle(Vector3.up, -bestTransform2d.Angle); poseOfUpSpace = new Pose(position, rotation); lock (_visualizationLocker) { _matchVisualization = new MatchVisualization( raysUpSpace.ToList(), poseOfUpSpace, projections.Select(p => bestTransform2d.apply(p)).ToList(), markersIndices); } return(true); }