1
1
using UnityEngine ;
2
2
using System . Collections ;
3
+ using System . Collections . Generic ;
4
+ using System ;
3
5
4
6
namespace HoloLensWithOpenCVForUnityExample
5
7
{
8
+ public struct PoseData {
9
+ public Vector3 pos ;
10
+ public Quaternion rot ;
11
+ }
12
+
6
13
/// <summary>
7
14
/// AR utils.
8
15
/// </summary>
9
16
public class ARUtils
10
17
{
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
+
11
143
/// <summary>
12
144
/// Extract translation from transform matrix.
13
145
/// </summary>
@@ -92,5 +224,99 @@ public static void SetTransformFromMatrix (Transform transform, ref Matrix4x4 ma
92
224
transform . localRotation = ExtractRotationFromMatrix ( ref matrix ) ;
93
225
transform . localScale = ExtractScaleFromMatrix ( ref matrix ) ;
94
226
}
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
+ }
95
321
}
96
322
}
0 commit comments