InfraredDemo.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using SmartBowSDK;
  6. using InfraredManager;
  7. using ZIM;
  8. using SLAMUVC;
  9. using System;
  10. /// <summary>
  11. /// 红外 + 蓝牙的使用示例脚本
  12. /// </summary>
  13. public class InfraredDemo : MonoBehaviour
  14. {
  15. public static InfraredDemo _ins;
  16. public static double MapValue(double value, double originalMin, double originalMax, double targetMin, double targetMax)
  17. {
  18. // 线性插值公式
  19. return targetMin + (value - originalMin) * (targetMax - targetMin) / (originalMax - originalMin);
  20. }
  21. private void Awake()
  22. {
  23. _ins = this;
  24. }
  25. void Start()
  26. {
  27. InitBluetoothModule();
  28. InitInfraredCamera();
  29. }
  30. void Update()
  31. {
  32. UpdateBluetoothModule();
  33. UpdateInfraredCamera();
  34. }
  35. #region 红外摄像
  36. public static bool running { get => infraredCameraHelper != null; }
  37. public static InfraredCameraHelper infraredCameraHelper { get; set; }
  38. [SerializeField] RawImage _cameraRender;
  39. [SerializeField] RawImage _imageScreenLocateManual;
  40. [SerializeField] List<RectTransform> _crosshairsInCamera;
  41. [SerializeField] Slider _sliderBrightness;
  42. [SerializeField] Slider _sliderContrast;
  43. [SerializeField] Slider _sliderShakeFilter;
  44. [SerializeField] Button _btnReset;
  45. [SerializeField] Button _btnScreenLocateManual;
  46. [SerializeField] Button _btnScreenLocateManualAuto;
  47. [SerializeField] Dropdown _dropdownResolution;
  48. [SerializeField] Text _fpsText;
  49. int frames;
  50. float lastCheckTime;
  51. //屏幕上ui的点
  52. List<Vector2> _screenLocatePoints = new();
  53. //屏幕内的点
  54. List<Vector2> _locatePointList = new();
  55. //public ParamFloatValue brightness = new ParamFloatValue("ic_brightness", 50.0f);
  56. // public ParamFloatValue contrast = new ParamFloatValue("ic_contrast", 50.0f);
  57. public ParamFloatValue shakeFilterValue = new ParamFloatValue("ic_shakeFilterValue2", 6.0f);
  58. public ParamFloatValue resoution = new ParamFloatValue("ic_resoution2", 2);
  59. string[] sliderNameArray = new string[]{
  60. "亮度", //
  61. "对比度"};
  62. string[] sliderStrArray = new string[]{
  63. "PU_BRIGHTNESS",
  64. "PU_CONTRAST"};
  65. UVCManager.CameraInfo currentCameraInfo;
  66. void InitInfraredCamera()
  67. {
  68. //SDK创建
  69. Vector2 saveResolution = GetResolution((int)resoution.Get());
  70. infraredCameraHelper = InfraredCameraHelper.GetInstance();
  71. infraredCameraHelper.Create((int)saveResolution.x, (int)saveResolution.y);
  72. //位置更新
  73. infraredCameraHelper.OnPositionUpdate += (Vector2 point) =>
  74. {
  75. Ray ray = Camera.main.ScreenPointToRay(point);
  76. Vector3 rayEndPoint = ray.GetPoint(200);
  77. Bow.Instance.transform.LookAt(rayEndPoint);
  78. };
  79. infraredCameraHelper.OnUVCIsReady += (UVCManager.CameraInfo camera) =>
  80. {
  81. if (currentCameraInfo != null) return;
  82. currentCameraInfo = camera;
  83. //生成控制摄像机的参数滑条
  84. Debug.Log("初始化摄像机!");
  85. //参数面板
  86. for (int i = 0; i < sliderStrArray.Length; i++)
  87. {
  88. string typeStr = sliderStrArray[i];
  89. UVCCtrlInfo _UVCCtrlInfo = camera.GetInfo(typeStr);
  90. int _curValue = _UVCCtrlInfo.current;
  91. //指定默认值
  92. //5、UVC亮度 - 50
  93. //6、UVC对比度 - 50
  94. if (typeStr == "PU_BRIGHTNESS")
  95. {
  96. _sliderBrightness.minValue = _UVCCtrlInfo.min;
  97. _sliderBrightness.maxValue = _UVCCtrlInfo.max;
  98. _sliderBrightness.wholeNumbers = true;
  99. SetBrightness(typeStr, _curValue);
  100. _sliderBrightness.onValueChanged.AddListener((newValue) =>
  101. {
  102. SetBrightness(typeStr, newValue);
  103. });
  104. }
  105. else if (typeStr == "PU_CONTRAST")
  106. {
  107. _sliderContrast.minValue = _UVCCtrlInfo.min;
  108. _sliderContrast.maxValue = _UVCCtrlInfo.max;
  109. _sliderContrast.wholeNumbers = true;
  110. SetContrast(typeStr, _curValue);
  111. _sliderContrast.onValueChanged.AddListener((newValue) =>
  112. {
  113. SetContrast(typeStr, newValue);
  114. });
  115. }
  116. }
  117. SetShakeFilterValue(shakeFilterValue.Get());
  118. _sliderShakeFilter.onValueChanged.AddListener(SetShakeFilterValue);
  119. //功能按钮
  120. _btnReset.onClick.AddListener(OnClick_Reset);
  121. _btnScreenLocateManual.onClick.AddListener(OnClick_ScreenLocateManual);
  122. _btnScreenLocateManualAuto.onClick.AddListener(OnClick_ScreenLocateAuto);
  123. //分辨率修改
  124. _dropdownResolution.onValueChanged.AddListener(v =>
  125. {
  126. SetResolution(v);
  127. });
  128. //算法红外阈值
  129. infraredCameraHelper.SetInfraredLocateBrightnessThreshold(0.8f);
  130. };
  131. //屏幕变化时候
  132. infraredCameraHelper.OnUVCPosUpdate += (list) =>
  133. {
  134. Debug.Log("OnUVCPosUpdate");
  135. SetLocatePointsToCameraRender(list, 1, 1);
  136. };
  137. }
  138. void UpdateInfraredCamera()
  139. {
  140. if (infraredCameraHelper == null) return;
  141. if (infraredCameraHelper.GetCameraTexture())
  142. {
  143. if (_cameraRender.texture == null || infraredCameraHelper.GetCameraTexture().GetNativeTexturePtr() != _cameraRender.texture.GetNativeTexturePtr())
  144. _cameraRender.texture = infraredCameraHelper.GetCameraTexture();
  145. }
  146. //手动定位
  147. if (infraredCameraHelper.IsScreenLocateManualDoing())
  148. {
  149. //引导提示
  150. string tipText = "单击屏幕 左下角";
  151. if (_screenLocatePoints.Count == 0) _locatePointList.Clear();
  152. if (_screenLocatePoints.Count == 1) tipText = "单击屏幕 右下角";
  153. if (_screenLocatePoints.Count == 2) tipText = "单击屏幕 右上角";
  154. if (_screenLocatePoints.Count == 3) tipText = "单击屏幕 左上角";
  155. _imageScreenLocateManual.transform.Find("Text").GetComponent<Text>().text = tipText;
  156. //点击检测
  157. if (Input.GetMouseButtonDown(0))
  158. {
  159. Vector2 mouse = Input.mousePosition;
  160. float u = Mathf.Clamp01(mouse.x / Screen.width);
  161. float v = Mathf.Clamp01(mouse.y / Screen.height);
  162. u = Math.Clamp(u, 0, 1);
  163. v = Math.Clamp(v, 0, 1);
  164. _locatePointList.Add(new Vector2(u, v));
  165. float texWidth = _imageScreenLocateManual.texture.width;
  166. float texHeight = _imageScreenLocateManual.texture.height;
  167. Vector2 texPoint = new Vector2(u * texWidth, v * texHeight);
  168. _screenLocatePoints.Add(texPoint);
  169. }
  170. //定位点显示
  171. Transform pointsTF = _imageScreenLocateManual.transform.Find("Points");
  172. for (int i = 0; i < pointsTF.childCount; i++)
  173. {
  174. Transform pointTF = pointsTF.GetChild(i);
  175. if (i < _screenLocatePoints.Count)
  176. {
  177. float texWidth = _imageScreenLocateManual.texture.width;
  178. float texHeight = _imageScreenLocateManual.texture.height;
  179. Vector2 texSize = new Vector2(texWidth, texHeight);
  180. Vector2 pos = _screenLocatePoints[i];
  181. pointTF.localPosition = pos.pixelToLocalPosition_AnchorCenter(texSize, _imageScreenLocateManual.rectTransform.rect);
  182. pointTF.gameObject.SetActive(true);
  183. }
  184. else pointTF.gameObject.SetActive(false);
  185. }
  186. //完成定位
  187. if (_screenLocatePoints.Count == 4)
  188. {
  189. _imageScreenLocateManual.gameObject.SetActive(false);
  190. SetLocatePointsToCameraRender(_screenLocatePoints, _imageScreenLocateManual.texture.width, _imageScreenLocateManual.texture.height);
  191. infraredCameraHelper.QuitScreenLocateManual(_locatePointList);
  192. }
  193. }
  194. //在相机画面显示准心
  195. if (ScreenLocate.Main)
  196. {
  197. var _sl = ScreenLocate.Main;
  198. var buffer = _sl.infraredSpotBuffer;
  199. if (buffer != null)
  200. {
  201. for (int i = 0; i < buffer.Length; i++)
  202. {
  203. if (buffer[i].CameraLocation != null)
  204. {
  205. //添加一个偏移量,使得最后输出的准心是指向正中心
  206. Vector2 newPoint2 = _sl.GetOffsetCameraLocation(buffer[i].CameraLocation.Value);
  207. // 检测到光点
  208. var pos = newPoint2.pixelToLocalPosition_AnchorCenter(_sl.mUVCCameraInfo.Size, _cameraRender.rectTransform.rect);
  209. _crosshairsInCamera[i].gameObject.SetActive(true);
  210. _crosshairsInCamera[i].anchoredPosition = pos;
  211. }
  212. else
  213. _crosshairsInCamera[i].gameObject.SetActive(false);
  214. }
  215. }
  216. }
  217. //性能检测
  218. ++frames;
  219. float timeNow = Time.realtimeSinceStartup;
  220. const float UpdateInterval = 0.5f;
  221. if (timeNow > lastCheckTime + UpdateInterval)
  222. {
  223. float fps = (float)(frames / (timeNow - lastCheckTime));
  224. frames = 0;
  225. lastCheckTime = timeNow;
  226. _fpsText.text = "FPS:" + fps.ToString("f2");
  227. }
  228. }
  229. public void SetLocatePointsToCameraRender(List<Vector2> points, float w, float h)
  230. {
  231. Transform pointsTF2 = _cameraRender.transform.Find("Points");
  232. if (pointsTF2.childCount == points.Count)
  233. {
  234. Vector2 texSize = new Vector2(w, h);
  235. for (int i = 0; i < pointsTF2.childCount; i++)
  236. {
  237. Transform pointTF = pointsTF2.GetChild(i);
  238. Vector2 pos = points[i];
  239. pointTF.localPosition = pos.pixelToLocalPosition_AnchorCenter(texSize, _cameraRender.rectTransform.rect);
  240. pointTF.gameObject.SetActive(true);
  241. }
  242. }
  243. }
  244. /// <summary>
  245. /// 亮度
  246. /// </summary>
  247. /// <param name="typeStr"></param>
  248. /// <param name="v"></param>
  249. void SetBrightness(string typeStr, float v)
  250. {
  251. var _value = Mathf.FloorToInt(v);
  252. currentCameraInfo.SetValue(typeStr, _value);
  253. //brightness.Set(v);
  254. _sliderBrightness.SetValueWithoutNotify(v);
  255. _sliderBrightness.transform.Find("Value").GetComponent<Text>().text = v.ToString("f1");
  256. }
  257. /// <summary>
  258. /// 对比度
  259. /// </summary>
  260. /// <param name="typeStr"></param>
  261. /// <param name="v"></param>
  262. void SetContrast(string typeStr, float v)
  263. {
  264. var _value = Mathf.FloorToInt(v);
  265. currentCameraInfo.SetValue(typeStr, _value);
  266. //contrast.Set(v);
  267. _sliderContrast.SetValueWithoutNotify(v);
  268. _sliderContrast.transform.Find("Value").GetComponent<Text>().text = v.ToString("f1");
  269. }
  270. void SetShakeFilterValue(float v)
  271. {
  272. shakeFilterValue.Set(v);
  273. _sliderShakeFilter.SetValueWithoutNotify(shakeFilterValue.Get());
  274. _sliderShakeFilter.transform.Find("Value").GetComponent<Text>().text = shakeFilterValue.Get().ToString("f1");
  275. InfraredCameraHelper.GetInstance().SetShakeFilterValue(shakeFilterValue.Get());
  276. }
  277. void SetResolution(int optionIndex)
  278. {
  279. resoution.Set(optionIndex);
  280. _dropdownResolution.SetValueWithoutNotify(optionIndex);
  281. switch (optionIndex)
  282. {
  283. case 0:
  284. infraredCameraHelper.SetCameraResolutionNew(1280, 720);
  285. break;
  286. case 1:
  287. infraredCameraHelper.SetCameraResolutionNew(640, 360);
  288. break;
  289. case 2:
  290. infraredCameraHelper.SetCameraResolutionNew(320, 240);
  291. break;
  292. case 3:
  293. infraredCameraHelper.SetCameraResolutionNew(160, 120);
  294. break;
  295. }
  296. }
  297. Vector2 GetResolution(int optionIndex)
  298. {
  299. _dropdownResolution.SetValueWithoutNotify(optionIndex);
  300. Vector2 vect = new Vector2(320, 240);
  301. switch (optionIndex)
  302. {
  303. case 0:
  304. vect = new Vector2(1280, 720);
  305. break;
  306. case 1:
  307. vect = new Vector2(640, 360);
  308. break;
  309. case 2:
  310. vect = new Vector2(320, 240);
  311. break;
  312. case 3:
  313. vect = new Vector2(160, 120);
  314. break;
  315. }
  316. return vect;
  317. }
  318. void OnClick_Reset()
  319. {
  320. SetBrightness("PU_BRIGHTNESS", 50);
  321. SetContrast("PU_CONTRAST", 50);
  322. SetShakeFilterValue(6);
  323. }
  324. void OnClick_ScreenLocateManual()
  325. {
  326. if (infraredCameraHelper.IsScreenLocateManualDoing()) return;
  327. Texture2D texture2D = infraredCameraHelper.EnterScreenLocateManual();
  328. if (texture2D == null)
  329. {
  330. infraredCameraHelper.QuitScreenLocateManual(null);
  331. return;
  332. }
  333. _imageScreenLocateManual.texture = texture2D;
  334. //_imageScreenLocateManual.material = infraredCameraHelper.GetCameraMaterial();
  335. _screenLocatePoints.Clear();
  336. _imageScreenLocateManual.gameObject.SetActive(true);
  337. }
  338. void OnClick_ScreenLocateAuto()
  339. {
  340. infraredCameraHelper.EnterScreenLocateManualAuto();
  341. }
  342. public void OnClick_SetAdjustPointsOffset()
  343. {
  344. var _sl = ScreenLocate.Main;
  345. var buffer = _sl.infraredSpotBuffer;
  346. if (buffer != null)
  347. {
  348. for (int i = 0; i < buffer.Length; i++)
  349. {
  350. if (buffer[i].CameraLocation != null)
  351. {
  352. Debug.Log("CameraLocation:" + buffer[i].CameraLocation.Value);
  353. var centerOffset = infraredCameraHelper.GetCenterOffset(buffer[i].CameraLocation.Value, "CameraLocation");
  354. Debug.Log("CenterOffset: " + centerOffset);
  355. var uvCenterOffset = infraredCameraHelper.GetCenterOffset(buffer[i].ScreenUV.Value, "ScreenUV");
  356. Debug.Log("UvCenterOffset: " + uvCenterOffset);
  357. }
  358. }
  359. }
  360. }
  361. #endregion
  362. #region 蓝牙模块
  363. [SerializeField] Button _btnConnect;
  364. [SerializeField] Text _textMacAddress;
  365. [SerializeField] Text _textBattery;
  366. void InitBluetoothModule()
  367. {
  368. SmartBowHelper.GetInstance().OnBluetoothModuleInited += OnBluetoothModuleInited;
  369. SmartBowHelper.GetInstance().OnBluetoothError += OnBluetoothError;
  370. SmartBowHelper.GetInstance().OnShooting += OnShooting;
  371. _btnConnect.onClick.AddListener(OnClick_Connect);
  372. }
  373. void UpdateBluetoothModule()
  374. {
  375. //更新显示蓝牙状态
  376. BluetoothStatusEnum bluetoothStatus = SmartBowHelper.GetInstance().GetBluetoothStatus();
  377. Text btnConnectText = _btnConnect.GetComponentInChildren<Text>();
  378. if (bluetoothStatus == BluetoothStatusEnum.None) btnConnectText.text = "<color=blue>未连接</color>(点击连接)";
  379. if (bluetoothStatus == BluetoothStatusEnum.Connecting) btnConnectText.text = "<color=#FF670D>连接中</color>";
  380. if (bluetoothStatus == BluetoothStatusEnum.Connected)
  381. {
  382. if (SmartBowHelper.GetInstance().IsBluetoothModuleInited()) btnConnectText.text = "<color=green>已连接</color>(点击断开)";
  383. else btnConnectText.text = "<color=green>已连接</color><color=blue>(正在初始化)</color>";
  384. }
  385. //更新显示电量
  386. int battery = SmartBowHelper.GetInstance().GetBattery();
  387. _textBattery.text = battery > 0 ? $"电量值:{battery}" : "未获得电量值";
  388. //更新显示Mac地址
  389. string macAddress = SmartBowHelper.GetInstance().GetMacAddress();
  390. _textMacAddress.text = macAddress != null ? $"Mac地址:{macAddress}" : "未获得Mac地址";
  391. }
  392. void OnBluetoothModuleInited()
  393. {
  394. SmartBowHelper.GetInstance().StartRotationSensor();
  395. SmartBowHelper.GetInstance().StartShootingSensor();
  396. }
  397. void OnBluetoothError(BluetoothError error, string message)
  398. {
  399. Debug.Log("OnBluetoothError:" + error);
  400. if (error == BluetoothError.ScanNotFoundTargetDevice)
  401. {
  402. TipText.Show("连接失败,未发现目标设备!");
  403. return;
  404. }
  405. TipText.Show(message);
  406. }
  407. void OnShooting(float speed)
  408. {
  409. Bow.Instance.Shoot();
  410. }
  411. void OnClick_Connect()
  412. {
  413. if (SmartBowHelper.GetInstance().GetBluetoothStatus() == BluetoothStatusEnum.Connecting) return;
  414. if (SmartBowHelper.GetInstance().GetBluetoothStatus() == BluetoothStatusEnum.None)
  415. {
  416. SmartBowHelper.GetInstance().Connect("test", 1);
  417. return;
  418. }
  419. if (SmartBowHelper.GetInstance().GetBluetoothStatus() == BluetoothStatusEnum.Connected)
  420. {
  421. SmartBowHelper.GetInstance().Disconnect();
  422. return;
  423. }
  424. }
  425. #endregion
  426. }
  427. public class ParamFloatValue
  428. {
  429. private string _saveKey;
  430. private float _valueDefault;
  431. private bool _valueLoaded;
  432. private float _value;
  433. public ParamFloatValue(string saveKey, float valueDefault)
  434. {
  435. _saveKey = saveKey;
  436. _valueDefault = valueDefault;
  437. }
  438. public float Get()
  439. {
  440. if (!_valueLoaded) _value = PlayerPrefs.GetFloat(_saveKey, _valueDefault);
  441. return _value;
  442. }
  443. public void Set(float value)
  444. {
  445. _value = value;
  446. PlayerPrefs.SetFloat(_saveKey, _value);
  447. PlayerPrefs.Save();
  448. }
  449. }