11using UnityEngine ;
22using System . Collections ;
3+ using System . Collections . Generic ;
4+ using System ;
35
46namespace 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