@@ -18,7 +18,7 @@ namespace HoloLensWithOpenCVForUnityExample
1818 /// An example of marker based AR using OpenCVForUnity on Hololens.
1919 /// Referring to https://github.com/opencv/opencv_contrib/blob/master/modules/aruco/samples/detect_markers.cpp.
2020 /// </summary>
21- [ RequireComponent ( typeof ( WebCamTextureToMatHelper ) ) ]
21+ [ RequireComponent ( typeof ( HololensCameraStreamToMatHelper ) ) ]
2222 public class HoloLensArUcoExample : MonoBehaviour
2323 {
2424 [ HeaderAttribute ( "Preview" ) ]
@@ -54,12 +54,6 @@ public class HoloLensArUcoExample : MonoBehaviour
5454 /// </summary>
5555 public bool applyEstimationPose = true ;
5656
57- /// <summary>
58- /// The downscale ratio.
59- /// </summary>
60- [ TooltipAttribute ( "Factor by which the image will be scaled down before detection." ) ]
61- public float downscaleRatio = 3 ;
62-
6357 /// <summary>
6458 /// The dictionary identifier.
6559 /// </summary>
@@ -153,8 +147,12 @@ public class HoloLensArUcoExample : MonoBehaviour
153147 /// <summary>
154148 /// The webcam texture to mat helper.
155149 /// </summary>
156- WebCamTextureToMatHelper webCamTextureToMatHelper ;
150+ HololensCameraStreamToMatHelper webCamTextureToMatHelper ;
157151
152+ /// <summary>
153+ /// The image optimization helper.
154+ /// </summary>
155+ ImageOptimizationHelper imageOptimizationHelper ;
158156
159157 Mat grayMat ;
160158 Mat rgbMat4preview ;
@@ -175,12 +173,9 @@ public class HoloLensArUcoExample : MonoBehaviour
175173 double distCoeffs4 = 0.0 ; //tangential distortion coefficient p2.
176174 double distCoeffs5 = - 0.2388065 ; //radial distortion coefficient k3.
177175
178- bool isDetecting = false ;
179- bool hasUpdatedARTransformMatrix = false ;
180176 readonly static Queue < Action > ExecuteOnMainThread = new Queue < Action > ( ) ;
181177 System . Object sync = new System . Object ( ) ;
182- Mat rgbaMat4Thread ;
183- Mat downScaleRgbaMat ;
178+ Mat downScaleFrameMat ;
184179
185180 bool _isThreadRunning = false ;
186181 bool isThreadRunning {
@@ -190,15 +185,33 @@ bool isThreadRunning {
190185 _isThreadRunning = value ; }
191186 }
192187
188+ bool _isDetecting = false ;
189+ bool isDetecting {
190+ get { lock ( sync )
191+ return _isDetecting ; }
192+ set { lock ( sync )
193+ _isDetecting = value ; }
194+ }
195+
196+ bool _hasUpdatedARTransformMatrix = false ;
197+ bool hasUpdatedARTransformMatrix {
198+ get { lock ( sync )
199+ return _hasUpdatedARTransformMatrix ; }
200+ set { lock ( sync )
201+ _hasUpdatedARTransformMatrix = value ; }
202+ }
203+
193204 // Use this for initialization
194205 void Start ( )
195206 {
196- if ( downscaleRatio < 1 )
197- downscaleRatio = 1 ;
198-
199207 displayCameraPreviewToggle . isOn = displayCameraPreview ;
200208
201- webCamTextureToMatHelper = gameObject . GetComponent < WebCamTextureToMatHelper > ( ) ;
209+ imageOptimizationHelper = gameObject . GetComponent < ImageOptimizationHelper > ( ) ;
210+ webCamTextureToMatHelper = gameObject . GetComponent < HololensCameraStreamToMatHelper > ( ) ;
211+ #if NETFX_CORE
212+ webCamTextureToMatHelper . frameMatAcquired += OnFrameMatAcquired ;
213+ #endif
214+
202215 webCamTextureToMatHelper . Initialize ( ) ;
203216 }
204217
@@ -209,22 +222,23 @@ public void OnWebCamTextureToMatHelperInitialized ()
209222 {
210223 Debug . Log ( "OnWebCamTextureToMatHelperInitialized" ) ;
211224
212- Mat webCamTextureMat = webCamTextureToMatHelper . GetMat ( ) ;
225+ Mat webCamTextureMat = imageOptimizationHelper . GetDownScaleMat ( webCamTextureToMatHelper . GetMat ( ) ) ;
213226
214227 Debug . Log ( "Screen.width " + Screen . width + " Screen.height " + Screen . height + " Screen.orientation " + Screen . orientation ) ;
215228
216- float width = Mathf . Round ( webCamTextureMat . width ( ) / downscaleRatio ) ;
217- float height = Mathf . Round ( webCamTextureMat . height ( ) / downscaleRatio ) ;
229+ float width = webCamTextureMat . width ( ) ;
230+ float height = webCamTextureMat . height ( ) ;
218231
219232 texture = new Texture2D ( ( int ) width , ( int ) height , TextureFormat . RGB24 , false ) ;
233+
220234 previewQuad . GetComponent < MeshRenderer > ( ) . material . mainTexture = texture ;
221235 previewQuad . transform . localScale = new Vector3 ( 1 , height / width , 1 ) ;
222236 previewQuad . SetActive ( displayCameraPreview ) ;
223237
224238 double fx = this . fx ;
225239 double fy = this . fy ;
226- double cx = this . cx / downscaleRatio ;
227- double cy = this . cy / downscaleRatio ;
240+ double cx = this . cx / imageOptimizationHelper . downscaleRatio ;
241+ double cy = this . cy / imageOptimizationHelper . downscaleRatio ;
228242
229243 camMatrix = new Mat ( 3 , 3 , CvType . CV_64FC1 ) ;
230244 camMatrix . put ( 0 , 0 , fx ) ;
@@ -263,7 +277,7 @@ public void OnWebCamTextureToMatHelperInitialized ()
263277 Debug . Log ( "aspectratio " + aspectratio [ 0 ] ) ;
264278
265279
266- grayMat = new Mat ( webCamTextureMat . rows ( ) , webCamTextureMat . cols ( ) , CvType . CV_8UC3 ) ;
280+ grayMat = new Mat ( ) ;
267281 ids = new Mat ( ) ;
268282 corners = new List < Mat > ( ) ;
269283 rejected = new List < Mat > ( ) ;
@@ -288,9 +302,8 @@ public void OnWebCamTextureToMatHelperInitialized ()
288302 if ( webCamTextureToMatHelper . GetWebCamDevice ( ) . isFrontFacing ) {
289303 webCamTextureToMatHelper . flipHorizontal = true ;
290304 }
291-
292- rgbaMat4Thread = new Mat ( ) ;
293- downScaleRgbaMat = new Mat ( ) ;
305+
306+ downScaleFrameMat = new Mat ( ( int ) height , ( int ) width , CvType . CV_8UC4 ) ;
294307 rgbMat4preview = new Mat ( ) ;
295308 }
296309
@@ -301,7 +314,12 @@ public void OnWebCamTextureToMatHelperDisposed ()
301314 {
302315 Debug . Log ( "OnWebCamTextureToMatHelperDisposed" ) ;
303316
317+ #if ! NETFX_CORE
304318 StopThread ( ) ;
319+ lock ( sync ) {
320+ ExecuteOnMainThread . Clear ( ) ;
321+ }
322+ #endif
305323
306324 if ( grayMat != null )
307325 grayMat . Dispose ( ) ;
@@ -322,9 +340,6 @@ public void OnWebCamTextureToMatHelperDisposed ()
322340 if ( rotMat != null )
323341 rotMat . Dispose ( ) ;
324342
325- if ( rgbaMat4Thread != null )
326- rgbaMat4Thread . Dispose ( ) ;
327-
328343 if ( rgbMat4preview != null )
329344 rgbMat4preview . Dispose ( ) ;
330345 }
@@ -337,6 +352,104 @@ public void OnWebCamTextureToMatHelperErrorOccurred(WebCamTextureToMatHelper.Err
337352 Debug . Log ( "OnWebCamTextureToMatHelperErrorOccurred " + errorCode ) ;
338353 }
339354
355+ #if NETFX_CORE
356+ public void OnFrameMatAcquired ( Mat bgraMat , Matrix4x4 projectionMatrix , Matrix4x4 cameraToWorldMatrix )
357+ {
358+ downScaleFrameMat = imageOptimizationHelper . GetDownScaleMat ( bgraMat ) ;
359+
360+ if ( enableDetection ) {
361+
362+ Imgproc . cvtColor ( downScaleFrameMat , grayMat , Imgproc . COLOR_BGRA2GRAY ) ;
363+
364+ // Detect markers and estimate Pose
365+ Aruco . detectMarkers ( grayMat , dictionary , corners , ids , detectorParams , rejected , camMatrix , distCoeffs ) ;
366+
367+ if ( applyEstimationPose && ids . total ( ) > 0 ) {
368+ Aruco . estimatePoseSingleMarkers ( corners , markerLength , camMatrix , distCoeffs , rvecs , tvecs ) ;
369+
370+ for ( int i = 0 ; i < ids . total ( ) ; i ++ ) {
371+
372+ //This example can display ARObject on only first detected marker.
373+ if ( i == 0 ) {
374+
375+ // Position
376+ double [ ] tvec = tvecs . get ( i , 0 ) ;
377+
378+ // Rotation
379+ double [ ] rv = rvecs . get ( i , 0 ) ;
380+ Mat rvec = new Mat ( 3 , 1 , CvType . CV_64FC1 ) ;
381+ rvec . put ( 0 , 0 , rv [ 0 ] ) ;
382+ rvec . put ( 1 , 0 , rv [ 1 ] ) ;
383+ rvec . put ( 2 , 0 , rv [ 2 ] ) ;
384+ Calib3d . Rodrigues ( rvec , rotMat ) ;
385+
386+ transformationM . SetRow ( 0 , new Vector4 ( ( float ) rotMat . get ( 0 , 0 ) [ 0 ] , ( float ) rotMat . get ( 0 , 1 ) [ 0 ] , ( float ) rotMat . get ( 0 , 2 ) [ 0 ] , ( float ) tvec [ 0 ] ) ) ;
387+ transformationM . SetRow ( 1 , new Vector4 ( ( float ) rotMat . get ( 1 , 0 ) [ 0 ] , ( float ) rotMat . get ( 1 , 1 ) [ 0 ] , ( float ) rotMat . get ( 1 , 2 ) [ 0 ] , ( float ) tvec [ 1 ] ) ) ;
388+ transformationM . SetRow ( 2 , new Vector4 ( ( float ) rotMat . get ( 2 , 0 ) [ 0 ] , ( float ) rotMat . get ( 2 , 1 ) [ 0 ] , ( float ) rotMat . get ( 2 , 2 ) [ 0 ] , ( float ) ( tvec [ 2 ] / imageOptimizationHelper . downscaleRatio ) ) ) ;
389+
390+ transformationM . SetRow ( 3 , new Vector4 ( 0 , 0 , 0 , 1 ) ) ;
391+
392+ lock ( sync ) {
393+ // Right-handed coordinates system (OpenCV) to left-handed one (Unity)
394+ ARM = invertYM * transformationM ;
395+
396+ // Apply Z axis inverted matrix.
397+ ARM = ARM * invertZM ;
398+ }
399+
400+ hasUpdatedARTransformMatrix = true ;
401+
402+ break ;
403+ }
404+ }
405+ }
406+ }
407+
408+ Mat rgbMat4preview = null ;
409+ if ( displayCameraPreview ) {
410+ rgbMat4preview = new Mat ( ) ;
411+ Imgproc . cvtColor ( downScaleFrameMat , rgbMat4preview , Imgproc . COLOR_BGRA2RGB ) ;
412+
413+ if ( ids . total ( ) > 0 ) {
414+ Aruco . drawDetectedMarkers ( rgbMat4preview , corners , ids , new Scalar ( 255 , 0 , 0 ) ) ;
415+
416+ for ( int i = 0 ; i < ids . total ( ) ; i ++ ) {
417+ Aruco . drawAxis ( rgbMat4preview , camMatrix , distCoeffs , rvecs , tvecs , markerLength * 0.5f ) ;
418+ }
419+ }
420+ }
421+
422+
423+ UnityEngine . WSA . Application . InvokeOnAppThread ( ( ) => {
424+
425+ if ( ! webCamTextureToMatHelper . IsPlaying ( ) ) return ;
426+
427+ if ( displayCameraPreview ) {
428+ OpenCVForUnity . Utils . fastMatToTexture2D ( rgbMat4preview , texture ) ;
429+ }
430+
431+ if ( applyEstimationPose ) {
432+ if ( hasUpdatedARTransformMatrix ) {
433+ hasUpdatedARTransformMatrix = false ;
434+
435+ lock ( sync ) {
436+ // Apply camera transform matrix.
437+ ARM = arCamera . transform . localToWorldMatrix * ARM ;
438+ ARUtils . SetTransformFromMatrix ( arGameObject . transform , ref ARM ) ;
439+ }
440+ }
441+ }
442+
443+ bgraMat . Dispose ( ) ;
444+ if ( rgbMat4preview != null ) {
445+ rgbMat4preview . Dispose ( ) ;
446+ }
447+
448+ } , false ) ;
449+ }
450+
451+ #else
452+
340453 // Update is called once per frame
341454 void Update ( )
342455 {
@@ -351,7 +464,7 @@ void Update ()
351464 if ( enableDetection && ! isDetecting ) {
352465 isDetecting = true ;
353466
354- rgbaMat4Thread = webCamTextureToMatHelper . GetMat ( ) ;
467+ downScaleFrameMat = imageOptimizationHelper . GetDownScaleMat ( webCamTextureToMatHelper . GetMat ( ) ) ;
355468
356469 StartThread ( ThreadWorker ) ;
357470 }
@@ -398,12 +511,7 @@ private void ThreadWorker()
398511
399512 private void DetectARUcoMarker ( )
400513 {
401- if ( downscaleRatio == 1 ) {
402- downScaleRgbaMat = rgbaMat4Thread ;
403- } else {
404- Imgproc . resize ( rgbaMat4Thread , downScaleRgbaMat , new Size ( ) , 1.0 / downscaleRatio , 1.0 / downscaleRatio , Imgproc . INTER_LINEAR ) ;
405- }
406- Imgproc . cvtColor ( downScaleRgbaMat , grayMat , Imgproc . COLOR_RGBA2GRAY ) ;
514+ Imgproc . cvtColor ( downScaleFrameMat , grayMat , Imgproc . COLOR_RGBA2GRAY ) ;
407515
408516 // Detect markers and estimate Pose
409517 Aruco . detectMarkers ( grayMat , dictionary , corners , ids , detectorParams , rejected , camMatrix , distCoeffs ) ;
@@ -429,7 +537,7 @@ private void DetectARUcoMarker()
429537
430538 transformationM . SetRow ( 0 , new Vector4 ( ( float ) rotMat . get ( 0 , 0 ) [ 0 ] , ( float ) rotMat . get ( 0 , 1 ) [ 0 ] , ( float ) rotMat . get ( 0 , 2 ) [ 0 ] , ( float ) tvec [ 0 ] ) ) ;
431539 transformationM . SetRow ( 1 , new Vector4 ( ( float ) rotMat . get ( 1 , 0 ) [ 0 ] , ( float ) rotMat . get ( 1 , 1 ) [ 0 ] , ( float ) rotMat . get ( 1 , 2 ) [ 0 ] , ( float ) tvec [ 1 ] ) ) ;
432- transformationM . SetRow ( 2 , new Vector4 ( ( float ) rotMat . get ( 2 , 0 ) [ 0 ] , ( float ) rotMat . get ( 2 , 1 ) [ 0 ] , ( float ) rotMat . get ( 2 , 2 ) [ 0 ] , ( float ) ( tvec [ 2 ] / downscaleRatio ) ) ) ;
540+ transformationM . SetRow ( 2 , new Vector4 ( ( float ) rotMat . get ( 2 , 0 ) [ 0 ] , ( float ) rotMat . get ( 2 , 1 ) [ 0 ] , ( float ) rotMat . get ( 2 , 2 ) [ 0 ] , ( float ) ( tvec [ 2 ] / imageOptimizationHelper . downscaleRatio ) ) ) ;
433541
434542 transformationM . SetRow ( 3 , new Vector4 ( 0 , 0 , 0 , 1 ) ) ;
435543
@@ -450,7 +558,7 @@ private void DetectARUcoMarker()
450558 private void OnDetectionDone ( )
451559 {
452560 if ( displayCameraPreview ) {
453- Imgproc . cvtColor ( downScaleRgbaMat , rgbMat4preview , Imgproc . COLOR_RGBA2RGB ) ;
561+ Imgproc . cvtColor ( downScaleFrameMat , rgbMat4preview , Imgproc . COLOR_RGBA2RGB ) ;
454562
455563 if ( ids . total ( ) > 0 ) {
456564 Aruco . drawDetectedMarkers ( rgbMat4preview , corners , ids , new Scalar ( 255 , 0 , 0 ) ) ;
@@ -475,12 +583,17 @@ private void OnDetectionDone()
475583
476584 isDetecting = false ;
477585 }
586+ #endif
478587
479588 /// <summary>
480589 /// Raises the destroy event.
481590 /// </summary>
482591 void OnDestroy ( )
483592 {
593+ imageOptimizationHelper . Dispose ( ) ;
594+ #if NETFX_CORE
595+ webCamTextureToMatHelper . frameMatAcquired -= OnFrameMatAcquired ;
596+ #endif
484597 webCamTextureToMatHelper . Dispose ( ) ;
485598 }
486599
0 commit comments