ScreenLocate.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. #define ENABLE_LOG
  2. using Serenegiant.UVC;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. using UnityEngine;
  7. using UnityEngine.UI;
  8. using ZIM;
  9. using static Serenegiant.UVC.UVCManager;
  10. using Color = UnityEngine.Color;
  11. using InfraredManager;
  12. using System.Linq;
  13. [RequireComponent(typeof(Canvas))]
  14. public partial class ScreenLocate : MonoBehaviour
  15. {
  16. public InfraredCameraHelper InfraredCameraHelper;
  17. private const string TAG = "ScreenLocate#";
  18. enum Mode
  19. {
  20. InfraredLocate,
  21. ScreenMap,
  22. ScreenLocateManual
  23. }
  24. enum InfraredCount
  25. {
  26. Single,
  27. Double
  28. }
  29. enum Platform
  30. {
  31. Window,
  32. Android
  33. }
  34. Platform mPlatform = Platform.Android;
  35. // 2个灯,顺序根据红外灯的大小 由大到小, 坐标通过 InfraredSpot.ScreenUV 和 InfraredSpot.CameraLocation 获得
  36. public InfraredSpot[] InfraredSpots
  37. {
  38. get
  39. {
  40. infraredCount = InfraredCount.Double;
  41. return infraredSpotBuffer;
  42. }
  43. }
  44. // 1个灯, 坐标通过 InfraredSpot.ScreenUV 和 InfraredSpot.CameraLocation 获得
  45. public InfraredSpot InfraredSpotSingle
  46. {
  47. get
  48. {
  49. infraredCount = InfraredCount.Single;
  50. return infraredSpotBuffer[0];
  51. }
  52. }
  53. public InfraredSpot[] infraredSpotBuffer;
  54. InfraredCount infraredCount;
  55. public string GetInfraredCount() { return infraredCount.ToString(); }
  56. #region UVC 处理的对象
  57. public UVCManager mUVCManager;
  58. public UVCDrawer mUVCDrawer;
  59. public CameraInfo mUVCCameraInfo;
  60. public bool getUVCCameraInfo => mUVCCameraInfo != null ? true : false;
  61. public Vector2 getUVCCameraInfoSize => getUVCCameraInfo ? mUVCCameraInfo.Size : new Vector2(256, 256);
  62. private Texture mUVCTexture;
  63. public Texture getUVCTexture => mUVCTexture;
  64. private Texture2D mUVCTexture2D;
  65. // [SerializeField] Texture2DArray mUVCOutArray;
  66. #endregion
  67. public Text Info;
  68. public List<RectTransform> CrosshairInCamera;
  69. public List<RectTransform> CrosshairInScreen;
  70. public RectTransform ScreenQuad;
  71. public Toggle SaveToggle;
  72. public bool ShowScreenQuad = false;
  73. public RawImage rawImage;
  74. public RawImage rawImage1;
  75. public RawImage rawImage2;
  76. public RawImage rawImage3;
  77. public RawImage rawImage4;
  78. public RawImage rawImage5;
  79. public RawImage FullScreenImage;
  80. public InfraredSpotSettings InfraredSpotSettings;
  81. public Texture2D DebugScreenImage;
  82. // private SynchronizationContext mainContext;
  83. //是否单点显示
  84. public bool bSinglePoint = true;//默认单点识别
  85. bool bIdentifyRed = true;//默认设备红色
  86. bool bIdentifyGreen = true;
  87. #region 性能检测相关
  88. public Text m_UITime;
  89. const float m_UIUpdateInterval = 0.1f;
  90. float m_UIUpdateTimer = 0.0f;
  91. List<float> m_History = new List<float>(100);
  92. int m_ValidHistoryFrames = 0;
  93. float m_AverageTime = float.NaN;
  94. float m_MedianTime = float.NaN;
  95. float m_MinTime = float.NaN;
  96. float m_MaxTime = float.NaN;
  97. public float updateInterval = 0.5F;
  98. private double lastInterval;
  99. private int frames = 0;
  100. private float fps;
  101. public Text m_FPS;
  102. #endregion
  103. InfraredLocate infraredLocate;
  104. RectTransform canvas;
  105. Mode mode;
  106. List<Vector2> pointManual = new List<Vector2>();
  107. //o0.Project.WebCam o0WebCam = null;
  108. o0.Project.ScreenIdentification screenIdentification;
  109. public o0.Project.ScreenIdentification getScreenIdentification => screenIdentification;
  110. static public ScreenLocate Main;
  111. static public List<RawImage> DebugImage = new List<RawImage>();
  112. static public RectTransform BackQuad = null;
  113. static public void DebugTexture(int index, Texture texture)
  114. {
  115. Destroy(DebugImage[index].texture);
  116. DebugImage[index].texture = texture;
  117. }
  118. static public void SetScreen(UnityEngine.Color? color = null)
  119. {
  120. if (BackQuad == null)
  121. {
  122. var canvas = GameObject.Find("WebCameraView").GetComponent<RectTransform>();
  123. var background = canvas.Find("Background");
  124. BackQuad = background.GetChild(0).GetComponent<RectTransform>();
  125. }
  126. BackQuad.parent.gameObject.SetActive(color != null);
  127. BackQuad.GetComponent<RawImage>().color = color ?? Color.black;
  128. Debug.Log("SetScreen null." + BackQuad.name);
  129. }
  130. static public void SetScreen(Rect rect, UnityEngine.Color? color = null)
  131. {
  132. if (BackQuad == null)
  133. {
  134. var canvas = GameObject.Find("WebCameraView").GetComponent<RectTransform>();
  135. var background = canvas.Find("Background");
  136. BackQuad = background.GetChild(0).GetComponent<RectTransform>();
  137. }
  138. BackQuad.parent.gameObject.SetActive(color != null);
  139. BackQuad.anchorMin = rect.min;
  140. BackQuad.anchorMax = rect.max;
  141. BackQuad.GetComponent<RawImage>().color = color ?? Color.black;
  142. Debug.Log("SetScreen color." + BackQuad.name);
  143. }
  144. static void DebugBackQuad(Rect? rect = null)
  145. {
  146. if (BackQuad)
  147. {
  148. BackQuad.parent.GetComponent<RawImage>().enabled = false;
  149. BackQuad.GetComponent<RawImage>().color = Color.white;
  150. BackQuad.parent.gameObject.SetActive(!BackQuad.parent.gameObject.activeSelf);
  151. if (rect.HasValue)
  152. {
  153. BackQuad.anchorMin = rect.Value.min;
  154. BackQuad.anchorMax = rect.Value.max;
  155. }
  156. }
  157. }
  158. void Awake()
  159. {
  160. Main = this;
  161. //if (mUVCDrawer)
  162. // mUVCDrawer.StartPreviewAction += UVCIsReady;
  163. }
  164. void OnDestroy()
  165. {
  166. //if (mUVCDrawer)
  167. // mUVCDrawer.StartPreviewAction -= UVCIsReady;
  168. }
  169. void Start()
  170. {
  171. //mainContext = SynchronizationContext.Current;
  172. DebugImage.Add(rawImage);
  173. DebugImage.Add(rawImage1);
  174. DebugImage.Add(rawImage2);
  175. DebugImage.Add(rawImage3);
  176. DebugImage.Add(rawImage4);
  177. DebugImage.Add(rawImage5);
  178. DebugImage.Add(FullScreenImage);
  179. canvas = transform.GetComponent<RectTransform>();
  180. mode = Mode.InfraredLocate;
  181. //if (DebugScreenImage)
  182. //{
  183. // screenIdentification = new o0.Project.ScreenIdentification(new o0.Geometry2D.Vector<int>(DebugScreenImage.width, DebugScreenImage.height));
  184. // WebCamIsReady(DebugScreenImage);
  185. // screenIdentification.LocateScreen();
  186. //}
  187. infraredCount = InfraredCount.Single;
  188. #region 性能检测相关
  189. for (var i = 0; i < m_History.Capacity; ++i)
  190. {
  191. m_History.Add(0.0f);
  192. }
  193. lastInterval = Time.realtimeSinceStartup;
  194. frames = 0;
  195. #endregion
  196. }
  197. //ZIMWebCamera场景使用
  198. public void WebCamIsReady(Texture texture)
  199. {
  200. mPlatform = Platform.Window;
  201. mUVCTexture = texture;
  202. mUVCCameraInfo = new CameraInfo(mUVCTexture);
  203. brightness = 0;
  204. //UVC准备好
  205. InfraredCameraHelper?.InvokeOnUVCIsReady(mUVCCameraInfo);
  206. }
  207. //手机端UVCCamra使用
  208. public void UVCIsReady(Texture texture)
  209. {
  210. mPlatform = Platform.Android;
  211. //this.startUVCBtn.interactable = true;
  212. mUVCTexture = texture;
  213. //ARGB32
  214. //mUVCTexture2D = Texture2D.CreateExternalTexture(texture.width, texture.height, TextureFormat.ARGB32, false, true, texture.GetNativeTexturePtr()); //TextureToTexture2D(texture);
  215. //Debug.Log("mUVCTexture2D isReable:" + mUVCTexture2D.isReadable);
  216. //Debug.Log("mUVCTexture2D mipmapCount:" + (mUVCTexture2D.mipmapCount > 1));
  217. List<CameraInfo> cameraInfos = mUVCManager.GetAttachedDevices();
  218. mUVCCameraInfo = cameraInfos[cameraInfos.Count - 1];
  219. Debug.Log("mUVCCameraInfo InvokeOnUVCIsReady:" + mUVCCameraInfo);
  220. //UVC准备好
  221. InfraredCameraHelper?.InvokeOnUVCIsReady(mUVCCameraInfo);
  222. }
  223. public void startUVC()
  224. {
  225. }
  226. int brightness = 0;
  227. //public Text brightnessText;
  228. //public void SliderBrightness(Slider slider)
  229. //{
  230. // var _value = slider.value;
  231. // brightness = (int)_value;
  232. // brightnessText.text = (2 + brightness) + "";
  233. //}
  234. public void SetInfraredLocateBrightnessThreshold(float value) {
  235. if (infraredLocate != null)
  236. {
  237. if(value>=0 && value <=1)
  238. infraredLocate.SetBrightnessThreshold(value); // 参数是 红外灯的亮度阈值,阈值越小能够检测到的亮度就越低,默认值是0.93
  239. }
  240. }
  241. void Update()
  242. {
  243. ++frames;
  244. float timeNow = Time.realtimeSinceStartup;
  245. if (timeNow > lastInterval + updateInterval)
  246. {
  247. fps = (float)(frames / (timeNow - lastInterval));
  248. frames = 0;
  249. lastInterval = timeNow;
  250. }
  251. if (m_FPS != null)
  252. m_FPS.text = "FPS:" + fps.ToString("f2");
  253. if (mUVCCameraInfo == null) return;
  254. if (screenIdentification == null)
  255. {
  256. screenIdentification = new o0.Project.ScreenIdentification(mUVCTexture);
  257. }
  258. if (infraredLocate == null)
  259. {
  260. infraredLocate = new InfraredLocate(mUVCCameraInfo, screenIdentification, InfraredSpotSettings);
  261. float redfilterValue = PlayerPrefs.GetFloat("Init redFilterSliderValue", 0.8f);
  262. Debug.Log("Init Red filterValue:" + redfilterValue);
  263. infraredLocate.SetBrightnessThreshold(redfilterValue); // 参数是 红外灯的亮度阈值,阈值越小能够检测到的亮度就越低,默认值是0.93
  264. }
  265. if (mode == Mode.ScreenLocateManual)
  266. {
  267. //if (Input.GetMouseButtonDown(0))
  268. //{
  269. // var mouse = Input.mousePosition;
  270. // var u = mouse.x / Screen.width;
  271. // var v = mouse.y / Screen.height;
  272. // u = Math.Clamp(u, 0, 1);
  273. // v = Math.Clamp(v, 0, 1);
  274. // pointManual.Add(new Vector2(u * mUVCTexture.width, v * mUVCTexture.height));
  275. // var obj = Instantiate(Resources.Load("Point")) as GameObject;
  276. // obj.transform.SetParent(FullScreenImage.transform);
  277. // obj.transform.localPosition = new Vector2(u, v).pixelToLocalPosition_AnchorCenter(new Vector2(1, 1), FullScreenImage.rectTransform.rect);
  278. // if (pointManual.Count == 1)
  279. // Info.text = "左键单击屏幕 右下角";
  280. // else if (pointManual.Count == 2)
  281. // Info.text = "左键单击屏幕 右上角";
  282. // else if (pointManual.Count == 3)
  283. // Info.text = "左键单击屏幕 左上角";
  284. // else if (pointManual.Count == 4)
  285. // {
  286. // screenIdentification.LocateScreenManual(new OrdinalQuadrilateral(pointManual[0].o0Vector(), pointManual[1].o0Vector(), pointManual[3].o0Vector(), pointManual[2].o0Vector()));
  287. // pointManual.Clear();
  288. // ShowScreen(screenIdentification.Screen.Quad);
  289. // foreach (Transform i in FullScreenImage.transform)
  290. // Destroy(i.gameObject);
  291. // ToMode(Mode.InfraredLocate);
  292. // }
  293. //}
  294. return;
  295. }
  296. //var t0 = Time.realtimeSinceStartup;
  297. /* New*/
  298. //Debug.Log((mUVCCameraInfo != null) +" = "+ mUVCCameraInfo.IsPreviewing + " = "+ screenIdentification.Screen.Active);
  299. if (mUVCCameraInfo != null && mUVCCameraInfo.IsPreviewing) // 成功定位屏幕后才做红外识别
  300. {
  301. CreateUVCTexture2DIfNeeded();
  302. if (!screenIdentification.Update(mUVCTexture2D) )
  303. {
  304. if (!screenIdentification.Screen.Active) {
  305. //DebugTexture(1, mUVCTexture2D.zimAutoLightSimple());
  306. return;
  307. }
  308. if (mode == Mode.InfraredLocate)
  309. {
  310. //0,0, cameraTexture2D.width, cameraTexture2D.height,0
  311. var pixels = mUVCTexture2D.GetPixels(); // 从左往右、从下往上
  312. //InfraredSpots = infraredLocate.Update(pixels);
  313. if (bSinglePoint)
  314. infraredSpotBuffer = infraredLocate.UpdateSingle(pixels);
  315. else
  316. infraredSpotBuffer = infraredLocate.Update(pixels);
  317. if (mPlatform == Platform.Window) //渲染ui上面的点。进入游戏可以隐藏
  318. {
  319. for (int i = 0; i < infraredSpotBuffer.Length; i++)
  320. {
  321. if (infraredSpotBuffer[i].CameraLocation != null)
  322. {
  323. // 检测到光点
  324. var posInCanvas = infraredSpotBuffer[i].CameraLocation.Value.pixelToLocalPosition_AnchorCenter(mUVCCameraInfo.Size, rawImage.rectTransform.rect);
  325. CrosshairInCamera[i].gameObject.SetActive(true);
  326. CrosshairInCamera[i].anchoredPosition = posInCanvas;
  327. }
  328. else
  329. CrosshairInCamera[i].gameObject.SetActive(false);
  330. }
  331. }
  332. //手机端使用
  333. if (mPlatform == Platform.Android && infraredSpotBuffer.Length > 0)
  334. {
  335. int redIndex = 0;
  336. int greenIndex = 1;
  337. //仅仅第一个点显示(如果最大点出界了会闪烁)
  338. if (bSinglePoint)
  339. {
  340. redIndex = 0; //单点识别是,可以选择切换颜色
  341. if (infraredSpotBuffer[redIndex].ScreenUV != null)
  342. {
  343. string str = "Single:";
  344. Info.text = str + infraredSpotBuffer[redIndex].ScreenUV.Value.ToString("F4");
  345. //InfraredManager.ConnetDevicesSingle.ins.posAction?.Invoke(new Vector3(infraredSpotBuffer[redIndex].ScreenUV.Value.x * Screen.width, infraredSpotBuffer[redIndex].ScreenUV.Value.y * Screen.height, 0));
  346. onFilterPos(infraredSpotBuffer[redIndex].ScreenUV.Value);
  347. }
  348. }
  349. else
  350. {
  351. //雙點模式下選擇第一個點
  352. if (bIdentifyRed && !bIdentifyGreen)
  353. {
  354. if (infraredSpotBuffer[redIndex].ScreenUV != null)
  355. {
  356. Info.text = "Red" + redIndex + ":" + infraredSpotBuffer[redIndex].ScreenUV.Value.ToString("F4");
  357. //InfraredManager.ConnetDevicesSingle.ins.posAction?.Invoke(new Vector3(infraredSpotBuffer[redIndex].ScreenUV.Value.x * Screen.width, infraredSpotBuffer[redIndex].ScreenUV.Value.y * Screen.height, 0));
  358. onFilterPos2(infraredSpotBuffer[redIndex].ScreenUV.Value, redIndex);
  359. }
  360. else
  361. {
  362. Info.text = "未检测到红色最大点!";
  363. }
  364. }
  365. else if (!bIdentifyRed && bIdentifyGreen) {
  366. if (infraredSpotBuffer[greenIndex].ScreenUV != null)
  367. {
  368. Info.text = "Green:" + infraredSpotBuffer[greenIndex].ScreenUV.Value.ToString("F4");
  369. //InfraredManager.ConnetDevicesSingle.ins.posAction?.Invoke(new Vector3(infraredSpotBuffer[greenIndex].ScreenUV.Value.x * Screen.width, infraredSpotBuffer[greenIndex].ScreenUV.Value.y * Screen.height, 0));
  370. onFilterPos2(infraredSpotBuffer[greenIndex].ScreenUV.Value, greenIndex);
  371. }
  372. else
  373. {
  374. Info.text = "未检测到绿色点!";
  375. }
  376. }
  377. else
  378. {
  379. //两个不选择和两个全选都跑识别两个点
  380. //自動切換 检测到光点
  381. if (infraredSpotBuffer[redIndex].ScreenUV != null)
  382. {
  383. Info.text = "Red:" + infraredSpotBuffer[redIndex].ScreenUV.Value.ToString("F4");
  384. //InfraredManager.ConnetDevicesSingle.ins.posAction?.Invoke(new Vector3(infraredSpotBuffer[redIndex].ScreenUV.Value.x * Screen.width, infraredSpotBuffer[redIndex].ScreenUV.Value.y * Screen.height, 0));
  385. onFilterPos2(infraredSpotBuffer[redIndex].ScreenUV.Value, redIndex);
  386. }
  387. else if (infraredSpotBuffer[greenIndex].ScreenUV != null)
  388. {
  389. Info.text = "Green:" + infraredSpotBuffer[greenIndex].ScreenUV.Value.ToString("F4");
  390. //InfraredManager.ConnetDevicesSingle.ins.posAction?.Invoke(new Vector3(infraredSpotBuffer[greenIndex].ScreenUV.Value.x * Screen.width, infraredSpotBuffer[greenIndex].ScreenUV.Value.y * Screen.height, 0));
  391. onFilterPos2(infraredSpotBuffer[greenIndex].ScreenUV.Value, greenIndex);
  392. }
  393. else
  394. {
  395. Info.text = "未检测到点!";
  396. }
  397. }
  398. }
  399. }
  400. }
  401. }
  402. }
  403. //var t1 = Time.realtimeSinceStartup;
  404. //var dt = t1 - t0;
  405. //m_History[m_ValidHistoryFrames % m_History.Count] = dt;
  406. //++m_ValidHistoryFrames;
  407. //m_UIUpdateTimer += Time.deltaTime;
  408. //if (m_UIUpdateTimer >= m_UIUpdateInterval)
  409. //{
  410. // m_UIUpdateTimer = 0.0f;
  411. // if (m_ValidHistoryFrames >= m_History.Count)
  412. // {
  413. // m_ValidHistoryFrames = 0;
  414. // m_AverageTime = 0.0f;
  415. // m_MinTime = float.PositiveInfinity;
  416. // m_MaxTime = float.NegativeInfinity;
  417. // {
  418. // for (var i = 0; i < m_History.Count; i++)
  419. // {
  420. // var time = m_History[i];
  421. // m_AverageTime += time;
  422. // m_MinTime = Mathf.Min(m_MinTime, time);
  423. // m_MaxTime = Mathf.Max(m_MaxTime, time);
  424. // }
  425. // m_AverageTime /= m_History.Count;
  426. // }
  427. // {
  428. // m_History.Sort();
  429. // // Odd-length history?
  430. // if ((m_History.Count & 1) != 0)
  431. // {
  432. // m_MedianTime = m_History[m_History.Count / 2];
  433. // }
  434. // else
  435. // {
  436. // m_MedianTime = (m_History[m_History.Count / 2] + m_History[m_History.Count / 2 - 1]) / 2.0f;
  437. // }
  438. // }
  439. // }
  440. // var statistics = $"{m_History.Count} 帧样本:\naverage: {m_AverageTime * 1000.0f:F2}ms\nmedian: {m_MedianTime * 1000.0f:F2}ms\nmin: {m_MinTime * 1000.0f:F2}ms\nmax: {m_MaxTime * 1000.0f:F2}ms\n";
  441. // //Method: {m_Method} {UnityEngine.SceneManagement.SceneManager.GetActiveScene().name} |
  442. // if (m_UITime != null)
  443. // m_UITime.text = $"Cam: {mUVCCameraInfo.CurrentWidth}x{mUVCCameraInfo.CurrentHeight}{(mUVCTexture2D? ",T2D:" : "")}{(mUVCTexture2D? mUVCTexture2D.width+ "x" : "")}{(mUVCTexture2D ? mUVCTexture2D.height:"")} \nLast Frame: {dt * 1000.0f:F2}ms \n{statistics}";
  444. //}
  445. //UpdateInputs();
  446. }
  447. Vector2 targetPos = Vector2.zero;
  448. Vector2 movePos = Vector2.zero;
  449. int moveSpeed = 20;
  450. public float filterDis = 3.0f;
  451. void onFilterPos(Vector2 _vector2Pos) {
  452. Vector2 np = new Vector2(_vector2Pos.x * Screen.width, _vector2Pos.y * Screen.height); //_vector2Pos.pixelToLocalPosition_AnchorCenter(Vector2.one, (transform as RectTransform).rect);
  453. if (Vector2.Distance(np, targetPos) >= filterDis)
  454. {
  455. targetPos = np;
  456. //InfraredManager.ConnetDevicesSingle.ins.posAction?.Invoke(new Vector3(targetPos.x, targetPos.y, 0));
  457. InfraredCameraHelper.InvokeOnPositionUpdate(targetPos);
  458. }
  459. //movePos = Vector3.Lerp(movePos, targetPos, Time.deltaTime * moveSpeed);
  460. //InfraredManager.ConnetDevicesSingle.ins.posAction?.Invoke(new Vector3(movePos.x, movePos.y, 0));
  461. }
  462. Vector2[] _targetPoints2 = new Vector2[] { Vector2.zero, Vector2.zero };
  463. void onFilterPos2(Vector2 _vector2Pos, int index)
  464. {
  465. Vector2 np = new Vector2(_vector2Pos.x * Screen.width, _vector2Pos.y * Screen.height);
  466. if (Vector2.Distance(np, _targetPoints2[index]) >= filterDis)
  467. {
  468. _targetPoints2[index] = np;
  469. InfraredCameraHelper.InvokeOnPositionUpdate2(_targetPoints2[index], index);
  470. }
  471. }
  472. #region 自动识别
  473. int Capture = 30;
  474. int Delay = 30;
  475. public void BtnScreenLocate()
  476. {
  477. if (DebugScreenImage)
  478. {
  479. screenIdentification = new o0.Project.ScreenIdentification(new o0.Geometry2D.Vector<int>(DebugScreenImage.width, DebugScreenImage.height));
  480. WebCamIsReady(DebugScreenImage);
  481. CreateUVCTexture2DIfNeeded();
  482. }
  483. Debug.Log("BtnScreenLocate Capture:" + Capture + " ,Delay: " + Delay);
  484. screenIdentification.LocateScreen(Capture, Delay);
  485. }
  486. /**
  487. * 与UVC设备协商时
  488. * H.264是否优先协商
  489. * 仅安卓实机有效
  490. * true: H.264 > MJPEG > YUV
  491. * false: MJPEG > H.264 > YUV
  492. */
  493. public bool PreferH264 = false;
  494. private const int FRAME_TYPE_MJPEG = 0x000007;
  495. private const int FRAME_TYPE_H264 = 0x000014;
  496. public void Resize(int width, int height)
  497. {
  498. if (mUVCCameraInfo == null) return;
  499. bool PreferH264 = mUVCManager.PreferH264;
  500. int[] frameTypes = {
  501. PreferH264 ? FRAME_TYPE_H264 : FRAME_TYPE_MJPEG,
  502. PreferH264 ? FRAME_TYPE_MJPEG : FRAME_TYPE_H264,
  503. };
  504. foreach (var frameType in frameTypes)
  505. {
  506. Debug.Log("Resize frameType:" + frameType + " = " + width + " : " + height);
  507. if (UVCManager.onResize(mUVCCameraInfo.device.id, frameType, width, height) == 0)
  508. {
  509. Debug.Log("frameType:" + frameType);
  510. break;
  511. }
  512. }
  513. }
  514. #endregion
  515. public void BtnScreenMap()
  516. {
  517. ToMode(Mode.ScreenMap);
  518. }
  519. //进入手动定位屏幕
  520. public void BtnScreenLocateManual()
  521. {
  522. ToMode(Mode.ScreenLocateManual);
  523. }
  524. public static List<Vector2> quadUnityVectorList = new();
  525. // 标记屏幕的四个角
  526. public void ShowScreen(OrdinalQuadrilateral quad)
  527. {
  528. if (quad == null)
  529. {
  530. Info.text = "识别屏幕失败";
  531. return;
  532. }
  533. Info.text = "已识别到屏幕";
  534. if (ShowScreenQuad)
  535. {
  536. ScreenQuad.gameObject.SetActive(true);
  537. quadUnityVectorList.Clear();
  538. for (int i = 0; i < 4; i++)
  539. {
  540. //RectTransform t = ScreenQuad.GetChild(i) as RectTransform;
  541. //mUVCCameraInfo.Size
  542. //t.anchoredPosition = quad[i].UnityVector().pixelToLocalPosition_AnchorCenter(mUVCCameraInfo.Size, ScreenQuad.rect);
  543. //自动识别时候,记录四个点
  544. quadUnityVectorList.Add(quad[i].UnityVector());
  545. }
  546. SaveScreenLocateVectorList();
  547. SyncInfraredDemo();
  548. SyncInfraredScreenPositioningView();
  549. }
  550. }
  551. static public void SaveScreenLocateVectorList()
  552. {
  553. string saveStr = string.Join(';', quadUnityVectorList.Select(v => $"{v.x},{v.y}")); //,{v.z}
  554. Debug.Log(saveStr);
  555. PlayerPrefs.SetString("ScreenLocateVectorList", saveStr);
  556. }
  557. static public void GetScreenLocateVectorList() {
  558. string posListStr = PlayerPrefs.GetString("ScreenLocateVectorList", "");
  559. if (!string.IsNullOrWhiteSpace(posListStr))
  560. {
  561. quadUnityVectorList.Clear();
  562. quadUnityVectorList = posListStr.Split(';')
  563. .Select(s =>
  564. {
  565. string[] parts = s.Split(',');
  566. return new Vector2(float.Parse(parts[0]), float.Parse(parts[1]));
  567. })
  568. .ToList();
  569. }
  570. }
  571. public void SyncInfraredDemo() {
  572. if (quadUnityVectorList.Count == 0) return;
  573. Vector2 texSize = getUVCCameraInfoSize;
  574. Debug.Log("quadUnityVectorList" + quadUnityVectorList.Count);
  575. //同步到infaredDemo
  576. FindObjectOfType<InfraredDemo>()?.SetLocatePointsToCameraRender(
  577. quadUnityVectorList,
  578. texSize.x,
  579. texSize.y);
  580. }
  581. public void SyncInfraredScreenPositioningView() {
  582. if (quadUnityVectorList.Count == 0) return;
  583. //同步位置
  584. FindObjectOfType<InfraredScreenPositioningView>()?.SyncScreenPosition();
  585. }
  586. void ToMode(Mode mode)
  587. {
  588. if (this.mode == mode)
  589. return;
  590. if (mode == Mode.ScreenMap)
  591. {
  592. if (!screenIdentification.Screen.Active)
  593. {
  594. Info.text = "先定位屏幕";
  595. return;
  596. }
  597. Info.text = "按ESC退出";
  598. SetScreen(Color.black);
  599. Info.transform.SetAsLastSibling();
  600. this.mode = Mode.ScreenMap;
  601. }
  602. else if (mode == Mode.InfraredLocate)
  603. {
  604. Info.text = screenIdentification.Screen.Active ? "已定位屏幕" : "定位屏幕失败";
  605. //Info.text = "已识别到屏幕";
  606. SetScreen(null);
  607. foreach (var i in CrosshairInScreen)
  608. i.gameObject.SetActive(false);
  609. FullScreenImage.gameObject.SetActive(false);
  610. Info.transform.SetSiblingIndex(transform.childCount - 4);
  611. this.mode = Mode.InfraredLocate;
  612. DebugTexture(6, null);
  613. //DebugTexture(1, null); //null
  614. // rawImage1.texture = null;
  615. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  616. Console.WriteLine($"{TAG} Mode.InfraredLocate:已识别到屏幕:{ screenIdentification.Screen.Active}");
  617. #endif
  618. }
  619. else if (mode == Mode.ScreenLocateManual)
  620. {
  621. Info.text = "左键单击屏幕 左下角";
  622. FullScreenImage.gameObject.SetActive(true);
  623. Info.transform.SetSiblingIndex(transform.childCount - 1);
  624. // var newTex = WebCamera.webCamTexture.AutoLight(10);
  625. //DebugTexture(1, TextureToTexture2D(rawImage.texture));
  626. CreateUVCTexture2DIfNeeded();
  627. DebugTexture(6, mUVCTexture2D.zimAutoLight(brightness));
  628. //mUVCTexture2DTemp = TextureToTexture2D(mUVCCameraInfo.previewTexture);
  629. //DebugTexture(6, mUVCTexture2DTemp.zimAutoLight(brightness));
  630. this.mode = Mode.ScreenLocateManual;
  631. }
  632. }
  633. private Texture2D TextureToTexture2D(Texture texture)
  634. {
  635. Texture2D _texture2D = new Texture2D(texture.width, texture.height, TextureFormat.ARGB32, false, true);
  636. RenderTexture currentRT = RenderTexture.active;
  637. RenderTexture renderTexture = RenderTexture.GetTemporary(
  638. texture.width,
  639. texture.height,
  640. 0,
  641. RenderTextureFormat.ARGB32,
  642. RenderTextureReadWrite.Linear);
  643. Graphics.Blit(texture, renderTexture);
  644. RenderTexture.active = renderTexture;
  645. _texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
  646. _texture2D.Apply();
  647. RenderTexture.active = currentRT;
  648. RenderTexture.ReleaseTemporary(renderTexture);
  649. return _texture2D;
  650. }
  651. private void CreateUVCTexture2DIfNeeded()
  652. {
  653. if (mUVCTexture2D != null)
  654. Destroy(mUVCTexture2D);
  655. mUVCTexture2D = TextureToTexture2D(mUVCTexture);
  656. }
  657. #region DoubleButton
  658. private DateTime m_firstTime;
  659. private DateTime m_secondTime;
  660. private void Press()
  661. {
  662. Debug.Log("进入手动定位");
  663. BtnScreenLocateManual();
  664. resetTime();
  665. }
  666. public void OnDoubleClick()
  667. {
  668. //超时重置
  669. if (!m_firstTime.Equals(default(DateTime)))
  670. {
  671. var intervalTime = DateTime.Now - m_firstTime;
  672. float milliSeconds = intervalTime.Seconds * 1000 + intervalTime.Milliseconds;
  673. if (milliSeconds >= 400)
  674. resetTime();
  675. }
  676. // 按下按钮时对两次的时间进行记录
  677. if (m_firstTime.Equals(default(DateTime)))
  678. m_firstTime = DateTime.Now;
  679. else
  680. m_secondTime = DateTime.Now;
  681. // 在第二次点击触发,时差小于400ms触发
  682. if (!m_firstTime.Equals(default(DateTime)) && !m_secondTime.Equals(default(DateTime)))
  683. {
  684. var intervalTime = m_secondTime - m_firstTime;
  685. float milliSeconds = intervalTime.Seconds * 1000 + intervalTime.Milliseconds;
  686. if (milliSeconds < 400)
  687. Press();
  688. else
  689. resetTime();
  690. }
  691. }
  692. private void resetTime()
  693. {
  694. m_firstTime = default(DateTime);
  695. m_secondTime = default(DateTime);
  696. }
  697. #endregion
  698. #region 性能检测相关
  699. void InvalidateTimings()
  700. {
  701. m_ValidHistoryFrames = 0;
  702. m_AverageTime = float.NaN;
  703. m_MedianTime = float.NaN;
  704. m_MinTime = float.NaN;
  705. m_MaxTime = float.NaN;
  706. }
  707. void UpdateInputs()
  708. {
  709. //重置
  710. if (Input.GetKeyDown(KeyCode.UpArrow))
  711. {
  712. InvalidateTimings();
  713. }
  714. }
  715. #endregion
  716. }