AutomaticCapture.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*===============================================================================
  2. Copyright (C) 2022 Immersal - Part of Hexagon. All Rights Reserved.
  3. This file is part of the Immersal SDK.
  4. The Immersal SDK cannot be copied, distributed, or made available to
  5. third-parties for commercial purposes without written permission of Immersal Ltd.
  6. Contact sdk@immersal.com for licensing requests.
  7. ===============================================================================*/
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Net.Http;
  12. using System.Threading.Tasks;
  13. using UnityEngine;
  14. using Immersal.AR;
  15. using Immersal.REST;
  16. using UnityEngine.XR.ARFoundation;
  17. using UnityEngine.XR.ARSubsystems;
  18. namespace Immersal.Samples.Mapping
  19. {
  20. public class AutomaticCapture : MonoBehaviour
  21. {
  22. public Action OnMapSubmitted;
  23. public Action OnImageUploaded;
  24. protected bool m_bCaptureRunning = false;
  25. protected uint m_ImageRun = 0;
  26. protected int m_ImageIndex = 0;
  27. protected bool m_RgbCapture = false;
  28. protected ImmersalSDK m_Sdk = null;
  29. protected List<JobAsync> m_Jobs = new List<JobAsync>();
  30. protected int m_JobLock = 0;
  31. protected Camera m_MainCamera = null;
  32. void Start()
  33. {
  34. m_Sdk = ImmersalSDK.Instance;
  35. m_MainCamera = Camera.main;
  36. DirectoryInfo dataDir = new DirectoryInfo(tempImagePath);
  37. if (dataDir.Exists)
  38. {
  39. dataDir.Delete(true);
  40. }
  41. Directory.CreateDirectory(tempImagePath);
  42. #if UNITY_IOS
  43. UnityEngine.iOS.Device.SetNoBackupFlag(tempImagePath);
  44. #endif
  45. }
  46. private void Update()
  47. {
  48. if (m_JobLock == 1)
  49. return;
  50. if (m_Jobs.Count > 0)
  51. {
  52. m_JobLock = 1;
  53. RunJob(m_Jobs[0]);
  54. }
  55. }
  56. public string tempImagePath
  57. {
  58. get
  59. {
  60. return string.Format("{0}/Images", Application.persistentDataPath);
  61. }
  62. }
  63. virtual public async void Capture()
  64. {
  65. await Task.Delay(250);
  66. m_bCaptureRunning = true;
  67. float captureStartTime = Time.realtimeSinceStartup;
  68. float uploadStartTime = Time.realtimeSinceStartup;
  69. XRCpuImage image;
  70. ARCameraManager cameraManager = m_Sdk.cameraManager;
  71. var cameraSubsystem = cameraManager.subsystem;
  72. if (cameraSubsystem != null && cameraSubsystem.TryAcquireLatestCpuImage(out image))
  73. {
  74. JobCaptureAsync j = new JobCaptureAsync();
  75. j.run = (int)(m_ImageRun & 0xEFFFFFFF);
  76. j.index = m_ImageIndex++;
  77. j.anchor = false;
  78. if (AutomaticCaptureLocationProvider.Instance.gpsOn)
  79. {
  80. j.latitude = AutomaticCaptureLocationProvider.Instance.latitude;
  81. j.longitude = AutomaticCaptureLocationProvider.Instance.longitude;
  82. j.altitude = AutomaticCaptureLocationProvider.Instance.altitude;
  83. }
  84. else
  85. {
  86. j.latitude = j.longitude = j.altitude = 0.0;
  87. }
  88. ARHelper.GetIntrinsics(out j.intrinsics);
  89. Quaternion rot = m_MainCamera.transform.rotation;
  90. Vector3 pos = m_MainCamera.transform.position;
  91. ARHelper.GetRotation(ref rot);
  92. j.rotation = ARHelper.SwitchHandedness(Matrix4x4.Rotate(rot));
  93. j.position = ARHelper.SwitchHandedness(pos);
  94. int width = image.width;
  95. int height = image.height;
  96. byte[] pixels;
  97. int channels = 1;
  98. if (m_RgbCapture)
  99. {
  100. ARHelper.GetPlaneDataRGB(out pixels, image);
  101. channels = 3;
  102. }
  103. else
  104. {
  105. ARHelper.GetPlaneData(out pixels, image);
  106. }
  107. byte[] capture = new byte[channels * width * height + 1024];
  108. Task<icvCaptureInfo> captureTask = Task.Run(() =>
  109. {
  110. return Core.CaptureImage(capture, capture.Length, pixels, width, height, channels);
  111. });
  112. await captureTask;
  113. string path = string.Format("{0}/{1}", tempImagePath, System.Guid.NewGuid());
  114. using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(path)))
  115. {
  116. writer.Write(capture, 0, captureTask.Result.captureSize);
  117. }
  118. j.imagePath = path;
  119. j.encodedImage = "";
  120. j.OnStart += () =>
  121. {
  122. uploadStartTime = Time.realtimeSinceStartup;
  123. };
  124. j.OnResult += (SDKImageResult result) =>
  125. {
  126. float et = Time.realtimeSinceStartup - uploadStartTime;
  127. Debug.Log(string.Format("Image uploaded successfully in {0} seconds", et));
  128. OnImageUploaded?.Invoke();
  129. };
  130. j.Progress.ProgressChanged += (s, progress) =>
  131. {
  132. int value = (int)(100f * progress);
  133. Debug.Log(string.Format("Upload progress: {0}%", value));
  134. };
  135. j.OnError += (e) =>
  136. {
  137. Debug.Log(string.Format("Capture error: " + e));
  138. };
  139. m_Jobs.Add(j);
  140. image.Dispose();
  141. float elapsedTime = Time.realtimeSinceStartup - captureStartTime;
  142. Debug.Log(string.Format("Capture in {0} seconds", elapsedTime));
  143. }
  144. m_bCaptureRunning = false;
  145. }
  146. public void Construct(string mapName, bool preservePoses, bool isPublic)
  147. {
  148. JobConstructAsync j = new JobConstructAsync();
  149. j.name = mapName;
  150. j.featureCount = 600;
  151. j.preservePoses = preservePoses;
  152. j.windowSize = 0;
  153. j.OnResult += (SDKConstructResult result) =>
  154. {
  155. Debug.Log(string.Format("Started constructing a map width ID {0}, containing {1} images and detail level of {2}", result.id, result.size, j.featureCount));
  156. OnMapSubmitted?.Invoke();
  157. if (isPublic)
  158. {
  159. SetSharingMode(result.id, true);
  160. }
  161. };
  162. m_Jobs.Add(j);
  163. }
  164. public void SetSharingMode(int mapId, bool isPublic)
  165. {
  166. JobSetPrivacyAsync j = new JobSetPrivacyAsync();
  167. j.id = mapId;
  168. j.privacy = isPublic ? 1 : 0;
  169. j.OnResult += (SDKMapPrivacyResult result) =>
  170. {
  171. Debug.Log(string.Format("Sharing mode set successfully, set to: {0}", j.privacy));
  172. };
  173. m_Jobs.Add(j);
  174. }
  175. private async void RunJob(JobAsync j)
  176. {
  177. await j.RunJobAsync();
  178. if (m_Jobs.Count > 0)
  179. {
  180. m_Jobs.RemoveAt(0);
  181. }
  182. m_JobLock = 0;
  183. }
  184. internal void ImageRunUpdate()
  185. {
  186. long bin = System.DateTime.Now.ToBinary();
  187. uint data = (uint)bin ^ (uint)(bin >> 32);
  188. m_ImageRun = (m_ImageRun ^ data) * 16777619;
  189. }
  190. }
  191. }