XDKCloudSession.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Text;
  6. using Unity.Collections.LowLevel.Unsafe;
  7. using UnityEngine;
  8. using UnityEngine.Events;
  9. using Unity.Collections;
  10. using OpenCVForUnity.CoreModule;
  11. using OpenCVForUnity.ImgcodecsModule;
  12. using OpenCVForUnity.ImgprocModule;
  13. using OpenCVForUnity.UnityUtils;
  14. using OpenCVForUnity.Calib3dModule;
  15. //using NRKernal;
  16. namespace Seengene.XDKUnityPluginCloud {
  17. [RequireComponent(typeof(XDKCloudInterface))]
  18. public class XDKCloudSession : MonoBehaviour {
  19. #region Properties
  20. [SerializeField]
  21. private SvrManager m_SvrManager = null;
  22. /// <summary>
  23. /// 重定位间隔时间
  24. /// </summary>
  25. private float m_RelocationInterval = 0.1f;
  26. private float m_RelocationIntervalStart = 0.5f;
  27. private float m_RelocationIntervalSuccess = 1f;
  28. /// <summary>
  29. /// 网络定位SessionID是否初始化?
  30. /// </summary>
  31. private bool m_NetSessionIDInitialized = false;
  32. /// <summary>
  33. /// 相机内参是否初始化?
  34. /// 相机内参需要从JIMO机器本地的配置文件中读取
  35. /// 每台JIMO的相机内参是不相同的
  36. /// </summary>
  37. private bool m_CameraCalibrationInitialized = false;
  38. /// <summary>
  39. /// 云定位接口
  40. /// </summary>
  41. private XDKCloudInterface m_InterfaceInstance;
  42. /// 上一次空间映射位置、旋转、缩放
  43. private Vector3 m_PreviousPosition;
  44. private Quaternion m_PreviousRotation;
  45. private Vector3 m_PreviousScale;
  46. /// 空间映射位置、旋转、缩放
  47. private Vector3 m_SpatialPosition;
  48. private Quaternion m_SpatialRotation;
  49. private Vector3 m_SpatialScale;
  50. /// <summary>
  51. /// 重定位成功次数
  52. /// </summary>
  53. private int m_RelocSuccessCounter = 0;
  54. /// <summary>
  55. /// 给算法更新图片次数
  56. /// </summary>
  57. private int m_UpdataFrameCounter = 0;
  58. private Transform m_ARCameraTransform;
  59. private float m_ElapsedTime;
  60. private string m_ImageSavePath;
  61. private Int32 m_LastSeq;
  62. private float m_Scale;
  63. private string m_SessionID;
  64. private RelocationResponse m_LastRelocResponse = null;
  65. private CameraCalibration m_CameraCalibration = null;
  66. [SerializeField]
  67. private CameraCalibrationLoader.EyeType m_EyeType = CameraCalibrationLoader.EyeType.LeftEye;
  68. #endregion
  69. #region UnityAction
  70. /// <summary>
  71. /// 更新预览图事件
  72. /// </summary>
  73. public UnityAction<Texture> UpdatePreviewImageEvent;
  74. /// <summary>
  75. /// 空间映射事件
  76. /// </summary>
  77. public UnityAction<Vector3, Quaternion, Vector3, int> SpatialMappedEvent;
  78. /// <summary>
  79. /// 更新空间特征点事件
  80. /// </summary>
  81. public UnityAction<List<Vector3>> UpdateKeyPointsEvent;
  82. /// <summary>
  83. /// 首次定位成功事件
  84. /// </summary>
  85. public UnityAction OnFirstRelocationSuccessEvent;
  86. /// <summary>
  87. /// Debug回调事件
  88. /// </summary>
  89. public UnityAction<string, DebugInfoType> OnUpdateDebugInfoEvent;
  90. #endregion
  91. #region Unity Methods
  92. private void Awake() {
  93. m_InterfaceInstance = GetComponent<XDKCloudInterface>();
  94. }
  95. private void Start() {
  96. m_SpatialPosition = Vector3.zero;
  97. m_SpatialRotation = Quaternion.identity;
  98. m_SpatialScale = Vector3.one;
  99. m_PreviousPosition = Vector3.zero;
  100. m_PreviousRotation = Quaternion.identity;
  101. m_PreviousScale = Vector3.one;
  102. m_UpdataFrameCounter = 0;
  103. m_RelocSuccessCounter = 0;
  104. m_ElapsedTime = 0;
  105. // 清空缓存文文件
  106. m_ImageSavePath = Path.Combine(Application.persistentDataPath, "seengene");
  107. if (Directory.Exists(m_ImageSavePath))
  108. Directory.Delete(m_ImageSavePath, true);
  109. InintializeCameraCalibration();
  110. InintializeNetSessionID();
  111. }
  112. private void OnEnable() {
  113. m_InterfaceInstance.OnAuthorized += HandleAuthorizationResponse;
  114. m_InterfaceInstance.OnRelocated += HandleRelocationResponse;
  115. }
  116. private void OnDisable() {
  117. m_InterfaceInstance.OnAuthorized -= HandleAuthorizationResponse;
  118. m_InterfaceInstance.OnRelocated -= HandleRelocationResponse;
  119. }
  120. private void Update() {
  121. if (Input.GetKeyUp(KeyCode.Escape)) {
  122. Resources.UnloadUnusedAssets();
  123. GC.Collect();
  124. Application.Quit();
  125. }
  126. if (m_NetSessionIDInitialized && m_CameraCalibrationInitialized) {
  127. m_ElapsedTime += Time.deltaTime;
  128. if (m_ElapsedTime < m_RelocationInterval) return;
  129. m_ElapsedTime = 0f;
  130. GetLatestFrameCameraImageAndPose();
  131. }
  132. }
  133. #endregion
  134. #region Private Methods
  135. private void InintializeCameraCalibration() {
  136. m_CameraCalibration = CameraCalibrationLoader.GetCameraCalibration(m_EyeType);
  137. if (m_CameraCalibration != null) {
  138. Debug.LogFormat("初始化相机内参成功:{0}, {1}", m_EyeType, m_CameraCalibration.ToString());
  139. m_CameraCalibrationInitialized = true;
  140. } else {
  141. Debug.LogError("初始化相机内参失败!");
  142. }
  143. }
  144. private void InintializeNetSessionID() {
  145. m_RelocationInterval = m_RelocationIntervalStart;
  146. m_InterfaceInstance.Authorize();
  147. }
  148. private void HandleAuthorizationResponse(AuthorizationResponse response) {
  149. if (response.status == (int)MapQueryStatus.MAP_SUCCESS) {
  150. if (XDKConfigs.IfLogOn) Debug.Log("Authorize Succes!");
  151. m_SessionID = response.sessionID;
  152. m_Scale = (float)response.scale;
  153. m_NetSessionIDInitialized = true;
  154. } else if (response.status == (int)MapQueryStatus.MAP_FAIL) {
  155. Debug.LogError("Authorize Failed, Code: " + response.status);
  156. } else {
  157. Debug.LogError("Authorize Failed, Undefined Code: " + response.status);
  158. }
  159. }
  160. private void HandleRelocationResponse(RelocationResponse response) {
  161. switch (response.status) {
  162. case (int)RelocalizeQueryStatus.SUCCESS:
  163. if (XDKConfigs.IfLogOn) Debug.LogFormat("Relocation Succes! seq: {0}", response.seq);
  164. if (response.seq < m_LastSeq) return;
  165. m_LastSeq = response.seq;
  166. UpdateSpatialRoot(response);
  167. break;
  168. case (int)RelocalizeQueryStatus.FRAME_SUCCESS_BA_FAIL:
  169. if (XDKConfigs.IfLogOn)
  170. Debug.LogWarningFormat("Relocation Failed, QueryStatus: 1-{0}, seq: {1}", RelocalizeQueryStatus.FRAME_SUCCESS_BA_FAIL, response.seq);
  171. break;
  172. case (int)RelocalizeQueryStatus.MAP_FAIL:
  173. if (XDKConfigs.IfLogOn)
  174. Debug.LogWarningFormat("Relocation Failed, QueryStatus: 2-{0}, seq: {1}", RelocalizeQueryStatus.MAP_FAIL, response.seq);
  175. break;
  176. case (int)RelocalizeQueryStatus.RELOCALIZE_FAIL:
  177. if (XDKConfigs.IfLogOn)
  178. Debug.LogWarningFormat("Relocation Failed, QueryStatus: 3-{0}, seq: {1}", RelocalizeQueryStatus.RELOCALIZE_FAIL, response.seq);
  179. break;
  180. case (int)RelocalizeQueryStatus.BA_SESSION_EXPIRED:
  181. if (XDKConfigs.IfLogOn)
  182. Debug.LogWarningFormat("Relocation Failed, QueryStatus: 4-{0} ,seq: {1}", RelocalizeQueryStatus.BA_SESSION_EXPIRED, response.seq);
  183. Debug.LogError("服务器 Session 超时,尝试重新获取Session");
  184. m_NetSessionIDInitialized = false;
  185. m_SessionID = "";
  186. InintializeNetSessionID();
  187. break;
  188. default:
  189. break;
  190. }
  191. }
  192. /// <summary>
  193. /// 更新空间映射根坐标
  194. /// </summary>
  195. private void UpdateSpatialRoot(RelocationResponse response) {
  196. m_RelocSuccessCounter++;
  197. if (XDKConfigs.IfDebugOn) {
  198. if (MusicPlayer.Instance != null) {
  199. MusicPlayer.Instance.PlayMusic();
  200. }
  201. }
  202. if (m_LastRelocResponse != null) {
  203. float offset = 0;
  204. offset = CheckWithProjectPointsAndroid(response);
  205. if (XDKConfigs.IfLogOn)
  206. Debug.LogFormat("offset(反投影偏移量): {0}", offset);
  207. if (offset <= 10.0f) {
  208. m_LastRelocResponse = response;
  209. if (OnUpdateDebugInfoEvent != null) {
  210. string strDebug = string.Format("重定位成功 {0}! offset = {1},反投影偏移量结果小于10,故放弃本次位姿校正", m_RelocSuccessCounter, offset);
  211. OnUpdateDebugInfoEvent.Invoke(strDebug, DebugInfoType.GetSpatialMappingNative);
  212. }
  213. return;
  214. }
  215. }
  216. m_LastRelocResponse = response;
  217. List<double> pose = response.transform_ltg;
  218. if (pose.Count >= 16) {
  219. Matrix4x4 matrix = new Matrix4x4();
  220. matrix.m00 = (float)pose[0];
  221. matrix.m10 = (float)pose[1];
  222. matrix.m20 = (float)pose[2];
  223. matrix.m30 = (float)pose[3];
  224. matrix.m10 = (float)pose[4];
  225. matrix.m11 = (float)pose[5];
  226. matrix.m21 = (float)pose[6];
  227. matrix.m31 = (float)pose[7];
  228. matrix.m02 = (float)pose[8];
  229. matrix.m12 = (float)pose[9];
  230. matrix.m22 = (float)pose[10];
  231. matrix.m32 = (float)pose[11];
  232. matrix.m03 = (float)pose[12];
  233. matrix.m13 = (float)pose[13];
  234. matrix.m23 = (float)pose[14];
  235. matrix.m33 = (float)pose[15];
  236. matrix = matrix.transpose;
  237. matrix.m01 = -matrix.m01;
  238. matrix.m02 = -matrix.m02;
  239. matrix.m10 = -matrix.m10;
  240. matrix.m13 = -matrix.m13;
  241. matrix.m20 = -matrix.m20;
  242. matrix.m23 = -matrix.m23;
  243. m_SpatialPosition = matrix.GetPosition();
  244. m_SpatialPosition.z = -m_SpatialPosition.z;
  245. m_SpatialRotation = matrix.GetRotation();
  246. m_SpatialRotation.z = -m_SpatialRotation.z;
  247. m_SpatialRotation.w = -m_SpatialRotation.w;
  248. m_SpatialScale = new Vector3(m_Scale, m_Scale, m_Scale);
  249. }
  250. if (m_PreviousPosition != m_SpatialPosition || m_PreviousRotation != m_SpatialRotation || m_PreviousScale != m_SpatialScale) {
  251. m_PreviousPosition = m_SpatialPosition;
  252. m_PreviousRotation = m_SpatialRotation;
  253. m_PreviousScale = m_SpatialScale;
  254. SpatialMappedEvent?.Invoke(m_SpatialPosition, m_SpatialRotation, m_SpatialScale, m_RelocSuccessCounter);
  255. if (m_RelocSuccessCounter == 1) {
  256. m_RelocationInterval = m_RelocationIntervalSuccess;
  257. if (OnFirstRelocationSuccessEvent != null) {
  258. OnFirstRelocationSuccessEvent.Invoke();
  259. }
  260. }
  261. if (XDKConfigs.IfDebugOn) {
  262. if (response.point3d_vec != null && UpdateKeyPointsEvent != null) {
  263. UpdateKeyPointsEvent.Invoke(response.point3d_vec);
  264. }
  265. if (MusicPlayer.Instance != null) {
  266. MusicPlayer.Instance.PlayMusic();
  267. }
  268. string strDebug = string.Format("重定位成功 {0} : {1},{2},{3},{4}", m_RelocSuccessCounter, m_SpatialPosition.ToString("f2"),
  269. m_SpatialRotation.ToString("f2"), m_SpatialRotation.ToString("f2"), m_SpatialScale.ToString("f2"));
  270. if (XDKConfigs.IfLogOn) {
  271. Debug.Log(strDebug);
  272. }
  273. if (OnUpdateDebugInfoEvent != null)
  274. OnUpdateDebugInfoEvent.Invoke(strDebug, DebugInfoType.GetSpatialMappingNative);
  275. }
  276. }
  277. }
  278. private float CheckWithProjectPointsAndroid(RelocationResponse response) {
  279. // MatOfPoint3f objectPoints
  280. MatOfPoint3f objectPoints = new MatOfPoint3f();
  281. List<Point3> listPoint3 = new List<Point3>();
  282. for (int i = 0; i < response.point3d_vec.Count; i++) {
  283. Vector3 v3 = response.point3d_vec[i];
  284. Point3 p = new Point3(v3.x, v3.y, v3.z);
  285. listPoint3.Add(p);
  286. }
  287. objectPoints.fromList(listPoint3);
  288. //Debug.LogFormat("objectPoints; {0}", objectPoints.dump());
  289. // Mat rvec(Rotation vector)
  290. // Mat tvec(Translation vector)
  291. Mat p1T = new Mat(4, 4, CvType.CV_32FC1);
  292. Matrix4x4 matrixCam = response.cameraPos;
  293. float[] arrCamTrans =
  294. new float[] { matrixCam.m00, matrixCam.m10, matrixCam.m20, matrixCam.m30,
  295. matrixCam.m01, matrixCam.m11, matrixCam.m21, matrixCam.m31,
  296. matrixCam.m02, matrixCam.m12, matrixCam.m22, matrixCam.m32,
  297. matrixCam.m03, matrixCam.m13, matrixCam.m23, matrixCam.m33};
  298. //float[] arrCamTrans =
  299. // new float[] { matrixCam.m00, matrixCam.m01, matrixCam.m02, matrixCam.m03,
  300. // matrixCam.m10, matrixCam.m11, matrixCam.m12, matrixCam.m13,
  301. // matrixCam.m20, matrixCam.m21, matrixCam.m22, matrixCam.m23,
  302. // matrixCam.m30, matrixCam.m31, matrixCam.m32, matrixCam.m33};
  303. p1T.put(0, 0, arrCamTrans);
  304. //Debug.LogFormat("p1T(Before): {0}", p1T.dump());
  305. p1T.put(0, 1, -p1T.get(0, 1)[0]);
  306. p1T.put(0, 2, -p1T.get(0, 2)[0]);
  307. p1T.put(1, 0, -p1T.get(1, 0)[0]);
  308. p1T.put(1, 3, -p1T.get(1, 3)[0]);
  309. p1T.put(2, 0, -p1T.get(2, 0)[0]);
  310. p1T.put(2, 3, -p1T.get(2, 3)[0]);
  311. //Debug.LogFormat("p1T(After): {0}", p1T.dump());
  312. //Debug.LogFormat("p1T.row(3): {0}", p1T.row(3).dump());
  313. List<double> pose = m_LastRelocResponse.transform_ltg;
  314. Matrix4x4 matrixMap = new Matrix4x4();
  315. matrixMap.m00 = (float)pose[0];
  316. matrixMap.m10 = (float)pose[1];
  317. matrixMap.m20 = (float)pose[2];
  318. matrixMap.m30 = (float)pose[3];
  319. matrixMap.m01 = (float)pose[4];
  320. matrixMap.m11 = (float)pose[5];
  321. matrixMap.m21 = (float)pose[6];
  322. matrixMap.m31 = (float)pose[7];
  323. matrixMap.m02 = (float)pose[8];
  324. matrixMap.m12 = (float)pose[9];
  325. matrixMap.m22 = (float)pose[10];
  326. matrixMap.m32 = (float)pose[11];
  327. matrixMap.m03 = (float)pose[12];
  328. matrixMap.m13 = (float)pose[13];
  329. matrixMap.m23 = (float)pose[14];
  330. matrixMap.m33 = (float)pose[15];
  331. float[] arrMapTrans =
  332. new float[] { matrixMap.m00, matrixMap.m10, matrixMap.m20, matrixMap.m30,
  333. matrixMap.m01, matrixMap.m11, matrixMap.m21, matrixMap.m31,
  334. matrixMap.m02, matrixMap.m12, matrixMap.m22, matrixMap.m32,
  335. matrixMap.m03, matrixMap.m13, matrixMap.m23, matrixMap.m33};
  336. //float[] arrMapTrans =
  337. // new float[] { matrixMap.m00, matrixMap.m01, matrixMap.m02, matrixMap.m03,
  338. // matrixMap.m10, matrixMap.m11, matrixMap.m12, matrixMap.m13,
  339. // matrixMap.m20, matrixMap.m21, matrixMap.m22, matrixMap.m23,
  340. // matrixMap.m30, matrixMap.m31, matrixMap.m32, matrixMap.m33};
  341. Mat p2T = new Mat(4, 4, CvType.CV_32FC1);
  342. p2T.put(0, 0, arrMapTrans);
  343. //Debug.LogFormat("p2T: {0}", p2T.dump());
  344. //Debug.LogFormat("p2T.row(3): {0}", p2T.row(3).dump());
  345. Mat t12T = p1T.inv() * p2T;
  346. //Debug.LogFormat("t12T; {0}", t12T.dump());
  347. Mat cvMat = Mat.zeros(3, 3, t12T.type());
  348. Mat t = Mat.zeros(3, 1, t12T.type());
  349. t12T.rowRange(0, 3).colRange(0, 3).copyTo(cvMat);
  350. t12T.rowRange(0, 3).col(3).copyTo(t);
  351. Mat r = new Mat();
  352. Calib3d.Rodrigues(cvMat, r);
  353. //Debug.LogFormat("r: {0}", r.dump());
  354. //Debug.LogFormat("t: {0}", t.dump());
  355. // Mat cameraMatrix (Intrisic matrix)
  356. Mat intrisicMat = new Mat(3, 3, CvType.CV_64FC1);
  357. float focalLengthX = response.cameraCalibration.focal_length.x;
  358. float focalLengthY = response.cameraCalibration.focal_length.y;
  359. float principalPointX = response.cameraCalibration.principal_point.x;
  360. float principalPointY = response.cameraCalibration.principal_point.y;
  361. intrisicMat.put(0, 0,
  362. focalLengthX, 0, principalPointX,
  363. 0, focalLengthY, principalPointY,
  364. 0, 0, 1);
  365. //Debug.LogFormat("intrisicMat: {0}", intrisicMat.dump());
  366. // MatOfDouble distCoeffs
  367. MatOfDouble distCoeffs = new MatOfDouble(0, 0, 0, 0);
  368. //Debug.LogFormat("distCoeffs: {0}", distCoeffs.dump());
  369. // MatOfPoint2f imagePoints
  370. MatOfPoint2f tempVecPoints2D = new MatOfPoint2f();
  371. //Debug.LogFormat("tempVecPoints2D(before): {0}", tempVecPoints2D.dump());
  372. Calib3d.projectPoints(objectPoints, r, t, intrisicMat, distCoeffs, tempVecPoints2D);
  373. //Debug.LogFormat("tempVecPoints2D(after): {0}", tempVecPoints2D.dump());
  374. List<float> listDistance = new List<float>();
  375. for (int i = 0; i < tempVecPoints2D.toArray().Length; i++) {
  376. Point p = tempVecPoints2D.toArray()[i];
  377. Vector2 v2 = response.point2d_vec[i];
  378. float dis = Mathf.Pow(((float)p.x - v2.x) * ((float)p.x - v2.x) + ((float)p.y - v2.y) * ((float)p.y - v2.y), 0.5f);
  379. listDistance.Add(dis);
  380. }
  381. listDistance.Sort();
  382. //Debug.LogFormat("listDistance: {0}", Tools.ListFloatToString(listDistance));
  383. float total = 0;
  384. int num = 0;
  385. float last = 0;
  386. for (int i = 0; i < listDistance.Count; i++) {
  387. float f = listDistance[i];
  388. if (num > listDistance.Count / 2) {
  389. if (f > last * 3 && f > 10) {
  390. break;
  391. }
  392. }
  393. total = total + f;
  394. last = f;
  395. num++;
  396. }
  397. return total / num;
  398. }
  399. private void GetLatestFrameCameraImageAndPose() {
  400. if (!SvrManager.Instance.Initialized) return;
  401. if (!XDKConfigs.IfRelocationOn) return;
  402. int seq = m_UpdataFrameCounter++;
  403. int imageWidth = 640;
  404. int imageHeight = 400;
  405. bool outBUdate = true;
  406. uint outCurrFrameIndex = 0;
  407. ulong outFrameExposureNano = 0;
  408. byte[] outFrameData = new byte[imageWidth * imageHeight];
  409. float[] outTRDataArray = new float[7];
  410. TextureFormat textureFormat = TextureFormat.R8;
  411. // SvrPluginAndroid.SvrGetLatestQVRCameraFrameData(ref outBUdate, ref outCurrFrameIndex, ref outFrameExposureNano, outFrameData, outTRDataArray);
  412. SvrPluginAndroid.SvrGetLatestQVRCameraFrameDataNoTransform(ref outBUdate, ref outCurrFrameIndex, ref outFrameExposureNano, outFrameData, outTRDataArray);
  413. if (outBUdate) {
  414. /// 获取相机位姿 从接口
  415. Vector3 cameraPosition = new Vector3(outTRDataArray[4], outTRDataArray[5], outTRDataArray[6]);
  416. Quaternion cameraRotation = new Quaternion(outTRDataArray[0], outTRDataArray[1], outTRDataArray[2], outTRDataArray[3]);
  417. Debug.LogFormat("接口数据:position:{0},rotation:{1}", cameraPosition, cameraRotation);
  418. Vector3 posIn = cameraPosition;
  419. posIn.z = -posIn.z;
  420. Quaternion rotIn = cameraRotation;
  421. rotIn.z = -rotIn.z;
  422. rotIn.w = -rotIn.w;
  423. /// 获取head位姿,直接从场景中的head物体
  424. Transform head = m_SvrManager.head;
  425. Debug.LogFormat("Head:position:{0},rotation:{1}", head.position, head.rotation);
  426. //Vector3 posIn_Head = head.position;
  427. //posIn_Head.z = -posIn_Head.z;
  428. //Quaternion rotIn_Head = head.rotation;
  429. //rotIn_Head.z = -rotIn_Head.z;
  430. //rotIn_Head.w = -rotIn_Head.w;
  431. Matrix4x4 matFinal = Matrix4x4.TRS(posIn, rotIn, Vector3.one);
  432. matFinal = matFinal.transpose;
  433. // compress grayscale image data into JPG format.
  434. byte[] jpegBytes;
  435. jpegBytes = XDKTools.GetGrayTextureBytes(outFrameData, textureFormat, imageHeight, imageWidth);
  436. if (jpegBytes == null) {
  437. Debug.LogErrorFormat("第{0}张图片转单通道灰度图JPG格式时出错!", seq);
  438. return;
  439. }
  440. if (XDKConfigs.IfDebugOn) {
  441. string strDebug = string.Format("更新图片 {0}:", seq);
  442. if (OnUpdateDebugInfoEvent != null)
  443. OnUpdateDebugInfoEvent.Invoke(strDebug, DebugInfoType.UpdateFrameNative);
  444. if (XDKConfigs.IfSaveImages) {
  445. Texture2D texture = new Texture2D(imageWidth, imageHeight, textureFormat, false);
  446. texture.LoadImage(jpegBytes);
  447. texture.Apply();
  448. UpdatePreviewImageEvent?.Invoke(texture);
  449. SaveCameraImageToLocal(seq, jpegBytes);
  450. SaveCameraPoseDataToLocal(seq, matFinal, m_CameraCalibration);
  451. SaveCameraPoseOriginDataToLocal(seq, cameraPosition, cameraRotation, m_CameraCalibration);
  452. Debug.LogFormat("保存第{0}张图片成功!", seq);
  453. }
  454. }
  455. m_InterfaceInstance.Relocate(m_SessionID, seq, matFinal, m_CameraCalibration, jpegBytes);
  456. }
  457. }
  458. private void SaveCameraImageToLocal(int seq, byte[] imageBuffer) {
  459. if (!Directory.Exists(m_ImageSavePath)) Directory.CreateDirectory(m_ImageSavePath);
  460. File.WriteAllBytes(Path.Combine(m_ImageSavePath, seq + ".jpg"), imageBuffer);
  461. }
  462. private void SaveCameraPoseDataToLocal(int seq, Matrix4x4 cameraPose, CameraCalibration cameraCalibration) {
  463. if (!Directory.Exists(m_ImageSavePath)) Directory.CreateDirectory(m_ImageSavePath);
  464. // 计算相机内参
  465. float intrinsics_00 = cameraCalibration.focal_length.x;
  466. float intrinsics_01 = 0;
  467. float intrinsics_02 = cameraCalibration.principal_point.x;
  468. float intrinsics_10 = 0;
  469. float intrinsics_11 = cameraCalibration.focal_length.y;
  470. float intrinsics_12 = cameraCalibration.principal_point.y;
  471. float intrinsics_20 = 0;
  472. float intrinsics_21 = 0;
  473. float intrinsics_22 = 1;
  474. string poseData = string.Format(
  475. "{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15} {16} {17} {18} {19} {20} {21} {22} {23} {24}",
  476. cameraPose.m00, cameraPose.m01, cameraPose.m02, cameraPose.m03,
  477. cameraPose.m10, cameraPose.m11, cameraPose.m12, cameraPose.m13,
  478. cameraPose.m20, cameraPose.m21, cameraPose.m22, cameraPose.m32,
  479. cameraPose.m30, cameraPose.m31, cameraPose.m32, cameraPose.m33,
  480. intrinsics_00, intrinsics_01, intrinsics_02,
  481. intrinsics_10, intrinsics_11, intrinsics_12,
  482. intrinsics_20, intrinsics_21, intrinsics_22);
  483. File.WriteAllText(Path.Combine(m_ImageSavePath, seq + ".txt"), poseData);
  484. }
  485. private void SaveCameraPoseOriginDataToLocal(int seq, Vector3 cameraPosition, Quaternion cameraRotation, CameraCalibration cameraCalibration) {
  486. if (!Directory.Exists(m_ImageSavePath)) Directory.CreateDirectory(m_ImageSavePath);
  487. string poseDataOrigin = string.Format("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15}",
  488. cameraPosition.x, cameraPosition.y, cameraPosition.z, cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w,
  489. cameraCalibration.focal_length.x, 0, cameraCalibration.principal_point.x,
  490. 0, cameraCalibration.focal_length.y, cameraCalibration.principal_point.y,
  491. 0, 0, 1);
  492. File.WriteAllText(Path.Combine(m_ImageSavePath, seq + "-origin" + ".txt"), poseDataOrigin);
  493. }
  494. #endregion
  495. #region Public Methods
  496. /// <summary>
  497. /// 手动模拟首次定位成功
  498. /// </summary>
  499. public void SimulateFirstRelocatSuccess() {
  500. if (m_RelocSuccessCounter >= 1) return;
  501. m_RelocSuccessCounter = 1;
  502. if (OnFirstRelocationSuccessEvent != null) {
  503. OnFirstRelocationSuccessEvent.Invoke();
  504. }
  505. }
  506. #endregion
  507. }
  508. }