Skip to content

Commit 88a9a58

Browse files
committed
v1.0.0
Added low-pass filter option. Fixed the performance of AR cube projection. Updated HololensCameraStreamToMatHelper version to 1.0.3. Added DefineSymbol of DISABLE_HOLOLENSCAMSTREAM_API.
1 parent 0531f47 commit 88a9a58

File tree

12 files changed

+1145
-220
lines changed

12 files changed

+1145
-220
lines changed

Assets/HoloLensWithOpenCVForUnityExample/HoloLensArUcoExample/ARUtils.cs

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,145 @@
11
using UnityEngine;
22
using System.Collections;
3+
using System.Collections.Generic;
4+
using System;
35

46
namespace HoloLensWithOpenCVForUnityExample
57
{
8+
public struct PoseData {
9+
public Vector3 pos;
10+
public Quaternion rot;
11+
}
12+
613
/// <summary>
714
/// AR utils.
815
/// </summary>
916
public class ARUtils
1017
{
18+
/// <summary>
19+
/// Convertes rvec value to rotation transform.
20+
/// </summary>
21+
/// <param name="tvec">Rvec.</param>
22+
/// <returns>Rotation.</returns>
23+
public static Quaternion ConvertRvecToRot (double[] rvec)
24+
{
25+
Vector3 _rvec = new Vector3((float)rvec[0], (float)rvec[1], (float)rvec[2]);
26+
float theta = _rvec.magnitude;
27+
_rvec.Normalize();
28+
29+
// http://stackoverflow.com/questions/12933284/rodrigues-into-eulerangles-and-vice-versa
30+
return Quaternion.AngleAxis(theta * Mathf.Rad2Deg, _rvec);
31+
}
32+
33+
/// <summary>
34+
/// Convertes tvec value to position transform.
35+
/// </summary>
36+
/// <param name="tvec">Tvec.</param>
37+
/// <returns>Position.</returns>
38+
public static Vector3 ConvertTvecToPos (double[] tvec)
39+
{
40+
return new Vector3((float)tvec[0], (float)tvec[1], (float)tvec[2]);
41+
}
42+
43+
/// <summary>
44+
/// Convertes rvec and tvec value to PoseData.
45+
/// </summary>
46+
/// <param name="tvec">Rvec.</param>
47+
/// <param name="tvec">Tvec.</param>
48+
/// <returns>PoseData.</returns>
49+
public static PoseData ConvertRvecTvecToPoseData (double[] rvec, double[] tvec)
50+
{
51+
PoseData data = new PoseData();
52+
data.pos = ConvertTvecToPos (tvec);
53+
data.rot = ConvertRvecToRot (rvec);
54+
55+
return data;
56+
}
57+
58+
/// <summary>
59+
/// Creates pose data dictionary.
60+
/// </summary>
61+
/// <param name="markerCount">Marker count.</param>
62+
/// <param name="ids">ids.</param>
63+
/// <param name="rvecs">Rvecs.</param>
64+
/// <param name="tvecs">Tvecs.</param>
65+
/// <returns>PoseData dictionary.</returns>
66+
public static Dictionary<int, PoseData> CreatePoseDataDict (int markerCount, int[] ids, double[] rvecs, double[] tvecs)
67+
{
68+
Dictionary<int, PoseData> dict = new Dictionary<int, PoseData>();
69+
if (markerCount == 0) return dict;
70+
71+
Vector3 rvec = new Vector3();
72+
for(int i = 0; i < markerCount; i++) {
73+
PoseData data = new PoseData();
74+
data.pos.Set((float)tvecs[i * 3], (float)tvecs[i * 3 + 1], (float)tvecs[i * 3 + 2]);
75+
76+
rvec.Set((float)rvecs[i * 3], (float)rvecs[i * 3 + 1], (float)rvecs[i * 3 + 2]);
77+
float theta = rvec.magnitude;
78+
rvec.Normalize();
79+
data.rot = Quaternion.AngleAxis(theta * Mathf.Rad2Deg, rvec);
80+
81+
dict[ids[i]] = data;
82+
}
83+
return dict;
84+
}
85+
86+
/// <summary>
87+
/// Performs a lowpass check on the position and rotation in newPose, comparing them to oldPose.
88+
/// </summary>
89+
/// <param name="oldPose">Old PoseData.</param>
90+
/// <param name="newPose">New PoseData.</param>
91+
/// <param name="posThreshold">Positon threshold.</param>
92+
/// <param name="rotThreshold">Rotation threshold.</param>
93+
public static void LowpassPoseData (ref PoseData oldPose, ref PoseData newPose, float posThreshold, float rotThreshold)
94+
{
95+
posThreshold *= posThreshold;
96+
97+
float posDiff = (newPose.pos - oldPose.pos).sqrMagnitude;
98+
float rotDiff = Quaternion.Angle(newPose.rot, oldPose.rot);
99+
100+
if (posDiff < posThreshold) {
101+
newPose.pos = oldPose.pos;
102+
}
103+
104+
if (rotDiff < rotThreshold) {
105+
newPose.rot = oldPose.rot;
106+
}
107+
}
108+
109+
/// <summary>
110+
/// Performs a lowpass check on the position and rotation of each marker in newDict, comparing them to those in oldDict.
111+
/// </summary>
112+
/// <param name="oldDict">Old dictionary.</param>
113+
/// <param name="newDict">New dictionary.</param>
114+
/// <param name="posThreshold">Positon threshold.</param>
115+
/// <param name="rotThreshold">Rotation threshold.</param>
116+
public static void LowpassPoseDataDict (Dictionary<int, PoseData> oldDict, Dictionary<int, PoseData> newDict, float posThreshold, float rotThreshold)
117+
{
118+
posThreshold *= posThreshold;
119+
120+
List<int> keys = new List<int>(newDict.Keys);
121+
foreach (int key in keys) {
122+
if (!oldDict.ContainsKey(key)) continue;
123+
124+
PoseData oldPose = oldDict[key];
125+
PoseData newPose = newDict[key];
126+
127+
float posDiff = (newPose.pos - oldPose.pos).sqrMagnitude;
128+
float rotDiff = Quaternion.Angle(newPose.rot, oldPose.rot);
129+
130+
if (posDiff < posThreshold) {
131+
newPose.pos = oldPose.pos;
132+
}
133+
134+
if (rotDiff < rotThreshold) {
135+
newPose.rot = oldPose.rot;
136+
}
137+
138+
newDict[key] = newPose;
139+
}
140+
}
141+
142+
11143
/// <summary>
12144
/// Extract translation from transform matrix.
13145
/// </summary>
@@ -92,5 +224,99 @@ public static void SetTransformFromMatrix (Transform transform, ref Matrix4x4 ma
92224
transform.localRotation = ExtractRotationFromMatrix (ref matrix);
93225
transform.localScale = ExtractScaleFromMatrix (ref matrix);
94226
}
227+
228+
/// <summary>
229+
/// Calculate projection matrix from camera matrix values.
230+
/// </summary>
231+
/// <param name="fx">Focal length x.</param>
232+
/// <param name="fy">Focal length y.</param>
233+
/// <param name="cx">Image center point x.(principal point x)</param>
234+
/// <param name="cy">Image center point y.(principal point y)</param>
235+
/// <param name="width">Image width.</param>
236+
/// <param name="height">Image height.</param>
237+
/// <param name="near">The near clipping plane distance.</param>
238+
/// <param name="far">The far clipping plane distance.</param>
239+
/// <returns>
240+
/// Projection matrix.
241+
/// </returns>
242+
public static Matrix4x4 CalculateProjectionMatrixFromCameraMatrixValues (float fx, float fy, float cx, float cy, float width, float height, float near, float far)
243+
{
244+
Matrix4x4 projectionMatrix = new Matrix4x4 ();
245+
projectionMatrix.m00 = 2.0f * fx / width;
246+
projectionMatrix.m02 = 1.0f - 2.0f * cx / width;
247+
projectionMatrix.m11 = 2.0f * fy / height;
248+
projectionMatrix.m12 = - 1.0f + 2.0f * cy / height;
249+
projectionMatrix.m22 = -(far + near) / (far - near);
250+
projectionMatrix.m23 = -2.0f * far * near / (far - near);
251+
projectionMatrix.m32 = -1.0f;
252+
253+
return projectionMatrix;
254+
}
255+
256+
/// <summary>
257+
/// Calculate camera matrix values from projection matrix.
258+
/// </summary>
259+
/// <param name="projectionMatrix">Projection matrix.</param>
260+
/// <param name="width">Image width.</param>
261+
/// <param name="height">Image height.</param>
262+
/// <param name="fovV">Vertical field of view.</param>
263+
/// <returns>
264+
/// Camera matrix values. (fx = matrx.m00, fy = matrx.m11, cx = matrx.m02, cy = matrx.m12)
265+
/// </returns>
266+
public static Matrix4x4 CameraMatrixValuesFromCalculateProjectionMatrix (Matrix4x4 projectionMatrix, float width, float height, float fovV)
267+
{
268+
float fovH = 2.0f * Mathf.Atan (width/height * Mathf.Tan (fovV*Mathf.Deg2Rad / 2.0f)) * Mathf.Rad2Deg;
269+
270+
Matrix4x4 cameraMatrix = new Matrix4x4 ();
271+
cameraMatrix.m00 = CalculateDistance (width, fovH);
272+
cameraMatrix.m02 = -((projectionMatrix.m02*width - width) / 2);
273+
cameraMatrix.m11 = CalculateDistance (height, fovV);
274+
cameraMatrix.m12 = (projectionMatrix.m12*height + height) / 2;
275+
cameraMatrix.m22 = 1.0f;
276+
277+
return cameraMatrix;
278+
}
279+
280+
/// <summary>
281+
/// Calculate frustum size.
282+
/// https://docs.unity3d.com/Manual/FrustumSizeAtDistance.html
283+
/// </summary>
284+
/// <param name="distance">Distance.</param>
285+
/// <param name="fov">Field of view. (horizontal or vertical direction)</param>
286+
/// <returns>
287+
/// Frustum height.
288+
/// </returns>
289+
public static float CalculateFrustumSize (float distance, float fov)
290+
{
291+
return 2.0f * distance * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
292+
}
293+
294+
/// <summary>
295+
/// Calculate distance.
296+
/// https://docs.unity3d.com/Manual/FrustumSizeAtDistance.html
297+
/// </summary>
298+
/// <param name="frustumHeight">One side size of a frustum.</param>
299+
/// <param name="fov">Field of view. (horizontal or vertical direction)</param>
300+
/// <returns>
301+
/// Distance.
302+
/// </returns>
303+
public static float CalculateDistance (float frustumSize, float fov)
304+
{
305+
return frustumSize * 0.5f / Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
306+
}
307+
308+
/// <summary>
309+
/// Calculate FOV angle.
310+
/// https://docs.unity3d.com/Manual/FrustumSizeAtDistance.html
311+
/// </summary>
312+
/// <param name="frustumHeight">One side size of a frustum.</param>
313+
/// <param name="distance">Distance.</param>
314+
/// <returns>
315+
/// FOV angle.
316+
/// </returns>
317+
public static float CalculateFOVAngle (float frustumSize, float distance)
318+
{
319+
return 2.0f * Mathf.Atan (frustumSize * 0.5f / distance) * Mathf.Rad2Deg;
320+
}
95321
}
96322
}

0 commit comments

Comments
 (0)