ScreenLocate.cs 35 KB

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