TransformECCExample.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. using OpenCVForUnity.CoreModule;
  2. using OpenCVForUnity.ImgprocModule;
  3. using OpenCVForUnity.UnityUtils;
  4. using OpenCVForUnity.UnityUtils.Helper;
  5. using OpenCVForUnity.VideoModule;
  6. using UnityEngine;
  7. using UnityEngine.EventSystems;
  8. using UnityEngine.SceneManagement;
  9. using UnityEngine.UI;
  10. namespace OpenCVForUnityExample
  11. {
  12. /// <summary>
  13. /// TransformECC Example
  14. /// An example of background movement tracking using ECC algorithm.
  15. /// </summary>
  16. [RequireComponent(typeof(WebCamTextureToMatHelper))]
  17. public class TransformECCExample : MonoBehaviour
  18. {
  19. /// <summary>
  20. /// The warp mode dropdown.
  21. /// </summary>
  22. public Dropdown warpModeDropdown;
  23. /// <summary>
  24. /// parameter, specifying the type of motion.
  25. /// </summary>
  26. public WarpModePreset warpMode = (WarpModePreset)Video.MOTION_EUCLIDEAN;
  27. float x;
  28. float y;
  29. Mat scalingMat;
  30. Mat grayMat;
  31. Mat lastGrayMat;
  32. // downscaling ratio.
  33. const float scaling = 3f;
  34. // Specify the number of iterations.
  35. const int number_of_iterations = 50; // 5000;
  36. // Specify the threshold of the increment
  37. // in the correlation coefficient between two iterations
  38. const double termination_eps = 1e-7; // 1e-10;
  39. // Define termination criteria
  40. TermCriteria criteria = new TermCriteria(TermCriteria.EPS | TermCriteria.COUNT, number_of_iterations, termination_eps);
  41. /// <summary>
  42. /// The stored touch point.
  43. /// </summary>
  44. Point storedTouchPoint;
  45. /// <summary>
  46. /// The texture.
  47. /// </summary>
  48. Texture2D texture;
  49. /// <summary>
  50. /// The webcam texture to mat helper.
  51. /// </summary>
  52. WebCamTextureToMatHelper webCamTextureToMatHelper;
  53. /// <summary>
  54. /// The FPS monitor.
  55. /// </summary>
  56. FpsMonitor fpsMonitor;
  57. // Use this for initialization
  58. void Start()
  59. {
  60. fpsMonitor = GetComponent<FpsMonitor>();
  61. webCamTextureToMatHelper = gameObject.GetComponent<WebCamTextureToMatHelper>();
  62. webCamTextureToMatHelper.Initialize();
  63. // Update GUI state
  64. warpModeDropdown.value = (int)warpMode;
  65. if (fpsMonitor != null)
  66. {
  67. fpsMonitor.consoleText = "Touch the screen to lock the point.";
  68. }
  69. }
  70. /// <summary>
  71. /// Raises the webcam texture to mat helper initialized event.
  72. /// </summary>
  73. public void OnWebCamTextureToMatHelperInitialized()
  74. {
  75. Debug.Log("OnWebCamTextureToMatHelperInitialized");
  76. Mat webCamTextureMat = webCamTextureToMatHelper.GetMat();
  77. texture = new Texture2D(webCamTextureMat.cols(), webCamTextureMat.rows(), TextureFormat.RGBA32, false);
  78. Utils.matToTexture2D(webCamTextureMat, texture);
  79. gameObject.GetComponent<Renderer>().material.mainTexture = texture;
  80. gameObject.transform.localScale = new Vector3(webCamTextureMat.cols(), webCamTextureMat.rows(), 1);
  81. Debug.Log("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
  82. if (fpsMonitor != null)
  83. {
  84. fpsMonitor.Add("width", webCamTextureMat.width().ToString());
  85. fpsMonitor.Add("height", webCamTextureMat.height().ToString());
  86. fpsMonitor.Add("orientation", Screen.orientation.ToString());
  87. }
  88. float width = webCamTextureMat.width();
  89. float height = webCamTextureMat.height();
  90. float widthScale = (float)Screen.width / width;
  91. float heightScale = (float)Screen.height / height;
  92. if (widthScale < heightScale)
  93. {
  94. Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;
  95. }
  96. else
  97. {
  98. Camera.main.orthographicSize = height / 2;
  99. }
  100. scalingMat = new Mat((int)(webCamTextureMat.rows() / scaling), (int)(webCamTextureMat.cols() / scaling), CvType.CV_8SC4);
  101. grayMat = new Mat(scalingMat.size(), CvType.CV_8SC1);
  102. x = scalingMat.cols() / 2f;
  103. y = scalingMat.rows() / 2f;
  104. //if true, The error log of the Native side OpenCV will be displayed on the Unity Editor Console.
  105. Utils.setDebugMode(true);
  106. }
  107. /// <summary>
  108. /// Raises the webcam texture to mat helper disposed event.
  109. /// </summary>
  110. public void OnWebCamTextureToMatHelperDisposed()
  111. {
  112. Debug.Log("OnWebCamTextureToMatHelperDisposed");
  113. if (scalingMat != null)
  114. {
  115. scalingMat.Dispose();
  116. scalingMat = null;
  117. }
  118. if (grayMat != null)
  119. {
  120. grayMat.Dispose();
  121. grayMat = null;
  122. }
  123. if (lastGrayMat != null)
  124. {
  125. lastGrayMat.Dispose();
  126. lastGrayMat = null;
  127. }
  128. if (texture != null)
  129. {
  130. Texture2D.Destroy(texture);
  131. texture = null;
  132. }
  133. Utils.setDebugMode(false, false);
  134. }
  135. /// <summary>
  136. /// Raises the webcam texture to mat helper error occurred event.
  137. /// </summary>
  138. /// <param name="errorCode">Error code.</param>
  139. public void OnWebCamTextureToMatHelperErrorOccurred(WebCamTextureToMatHelper.ErrorCode errorCode)
  140. {
  141. Debug.Log("OnWebCamTextureToMatHelperErrorOccurred " + errorCode);
  142. if (fpsMonitor != null)
  143. {
  144. fpsMonitor.consoleText = "ErrorCode: " + errorCode;
  145. }
  146. }
  147. // Update is called once per frame
  148. void Update()
  149. {
  150. #if ((UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR)
  151. //Touch
  152. int touchCount = Input.touchCount;
  153. if (touchCount == 1)
  154. {
  155. Touch t = Input.GetTouch(0);
  156. if(t.phase == TouchPhase.Ended && !EventSystem.current.IsPointerOverGameObject (t.fingerId)) {
  157. storedTouchPoint = new Point (t.position.x, t.position.y);
  158. //Debug.Log ("touch X " + t.position.x);
  159. //Debug.Log ("touch Y " + t.position.y);
  160. }
  161. }
  162. #else
  163. //Mouse
  164. if (Input.GetMouseButtonUp(0) && !EventSystem.current.IsPointerOverGameObject())
  165. {
  166. storedTouchPoint = new Point(Input.mousePosition.x, Input.mousePosition.y);
  167. //Debug.Log ("mouse X " + Input.mousePosition.x);
  168. //Debug.Log ("mouse Y " + Input.mousePosition.y);
  169. }
  170. #endif
  171. if (webCamTextureToMatHelper.IsPlaying() && webCamTextureToMatHelper.DidUpdateThisFrame())
  172. {
  173. if (storedTouchPoint != null)
  174. {
  175. ConvertScreenPointToTexturePoint(storedTouchPoint, storedTouchPoint, gameObject, texture.width, texture.height);
  176. x = (float)storedTouchPoint.x / scaling;
  177. y = (float)storedTouchPoint.y / scaling;
  178. storedTouchPoint = null;
  179. }
  180. Mat rgbaMat = webCamTextureToMatHelper.GetMat();
  181. Imgproc.resize(rgbaMat, scalingMat, new Size(rgbaMat.width() / scaling, rgbaMat.height() / scaling));
  182. Imgproc.cvtColor(scalingMat, grayMat, Imgproc.COLOR_RGBA2GRAY);
  183. if (lastGrayMat == null)
  184. lastGrayMat = grayMat.clone();
  185. // Define 2x3 or 3x3 matrices and initialize the matrix to identity
  186. Mat warp_matrix;
  187. if (warpMode == (WarpModePreset)Video.MOTION_HOMOGRAPHY)
  188. {
  189. warp_matrix = Mat.eye(3, 3, CvType.CV_32F);
  190. }
  191. else
  192. {
  193. warp_matrix = Mat.eye(2, 3, CvType.CV_32F);
  194. }
  195. // Run the ECC algorithm. The results are stored in warp_matrix.
  196. double ret = Video.findTransformECC(lastGrayMat, grayMat, warp_matrix, (int)warpMode, criteria);
  197. grayMat.copyTo(lastGrayMat);
  198. // Apply warp_matrix to x, y.
  199. Mat xyz = new Mat(3, 1, CvType.CV_32F);
  200. xyz.put(0, 0, x);
  201. xyz.put(1, 0, y);
  202. xyz.put(2, 0, 1.0);
  203. Mat result = warp_matrix.matMul(xyz);
  204. x = (float)result.get(0, 0)[0];
  205. y = (float)result.get(1, 0)[0];
  206. // Draw a box in the frame at x, y
  207. Imgproc.rectangle(rgbaMat, new Point((x * scaling) - 1, (y * scaling) - 1), new Point((x * scaling) + 1, (y * scaling) + 1), new Scalar(255, 0, 255, 255), 2);
  208. Imgproc.rectangle(rgbaMat, new Point((x * scaling) - 8, (y * scaling) - 8), new Point((x * scaling) + 8, (y * scaling) + 8), new Scalar(0, 255, 0, 255), 2);
  209. //Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false);
  210. Utils.matToTexture2D(rgbaMat, texture);
  211. }
  212. }
  213. /// <summary>
  214. /// Converts the screen point to texture point.
  215. /// </summary>
  216. /// <param name="screenPoint">Screen point.</param>
  217. /// <param name="dstPoint">Dst point.</param>
  218. /// <param name="texturQuad">Texture quad.</param>
  219. /// <param name="textureWidth">Texture width.</param>
  220. /// <param name="textureHeight">Texture height.</param>
  221. /// <param name="camera">Camera.</param>
  222. private void ConvertScreenPointToTexturePoint(Point screenPoint, Point dstPoint, GameObject textureQuad, int textureWidth = -1, int textureHeight = -1, Camera camera = null)
  223. {
  224. if (textureWidth < 0 || textureHeight < 0)
  225. {
  226. Renderer r = textureQuad.GetComponent<Renderer>();
  227. if (r != null && r.material != null && r.material.mainTexture != null)
  228. {
  229. textureWidth = r.material.mainTexture.width;
  230. textureHeight = r.material.mainTexture.height;
  231. }
  232. else
  233. {
  234. textureWidth = (int)textureQuad.transform.localScale.x;
  235. textureHeight = (int)textureQuad.transform.localScale.y;
  236. }
  237. }
  238. if (camera == null)
  239. camera = Camera.main;
  240. Vector3 quadPosition = textureQuad.transform.localPosition;
  241. Vector3 quadScale = textureQuad.transform.localScale;
  242. Vector2 tl = camera.WorldToScreenPoint(new Vector3(quadPosition.x - quadScale.x / 2, quadPosition.y + quadScale.y / 2, quadPosition.z));
  243. Vector2 tr = camera.WorldToScreenPoint(new Vector3(quadPosition.x + quadScale.x / 2, quadPosition.y + quadScale.y / 2, quadPosition.z));
  244. Vector2 br = camera.WorldToScreenPoint(new Vector3(quadPosition.x + quadScale.x / 2, quadPosition.y - quadScale.y / 2, quadPosition.z));
  245. Vector2 bl = camera.WorldToScreenPoint(new Vector3(quadPosition.x - quadScale.x / 2, quadPosition.y - quadScale.y / 2, quadPosition.z));
  246. using (Mat srcRectMat = new Mat(4, 1, CvType.CV_32FC2))
  247. using (Mat dstRectMat = new Mat(4, 1, CvType.CV_32FC2))
  248. {
  249. srcRectMat.put(0, 0, tl.x, tl.y, tr.x, tr.y, br.x, br.y, bl.x, bl.y);
  250. dstRectMat.put(0, 0, 0, 0, quadScale.x, 0, quadScale.x, quadScale.y, 0, quadScale.y);
  251. using (Mat perspectiveTransform = Imgproc.getPerspectiveTransform(srcRectMat, dstRectMat))
  252. using (MatOfPoint2f srcPointMat = new MatOfPoint2f(screenPoint))
  253. using (MatOfPoint2f dstPointMat = new MatOfPoint2f())
  254. {
  255. Core.perspectiveTransform(srcPointMat, dstPointMat, perspectiveTransform);
  256. dstPoint.x = dstPointMat.get(0, 0)[0] * textureWidth / quadScale.x;
  257. dstPoint.y = dstPointMat.get(0, 0)[1] * textureHeight / quadScale.y;
  258. }
  259. }
  260. }
  261. /// <summary>
  262. /// Raises the destroy event.
  263. /// </summary>
  264. void OnDestroy()
  265. {
  266. webCamTextureToMatHelper.Dispose();
  267. }
  268. /// <summary>
  269. /// Raises the back button click event.
  270. /// </summary>
  271. public void OnBackButtonClick()
  272. {
  273. SceneManager.LoadScene("OpenCVForUnityExample");
  274. }
  275. /// <summary>
  276. /// Raises the play button click event.
  277. /// </summary>
  278. public void OnPlayButtonClick()
  279. {
  280. webCamTextureToMatHelper.Play();
  281. }
  282. /// <summary>
  283. /// Raises the pause button click event.
  284. /// </summary>
  285. public void OnPauseButtonClick()
  286. {
  287. webCamTextureToMatHelper.Pause();
  288. }
  289. /// <summary>
  290. /// Raises the stop button click event.
  291. /// </summary>
  292. public void OnStopButtonClick()
  293. {
  294. webCamTextureToMatHelper.Stop();
  295. }
  296. /// <summary>
  297. /// Raises the change camera button click event.
  298. /// </summary>
  299. public void OnChangeCameraButtonClick()
  300. {
  301. webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.requestedIsFrontFacing;
  302. }
  303. /// <summary>
  304. /// Raises the warp mode dropdown value changed event.
  305. /// </summary>
  306. public void OnWarpModeDropdownValueChanged(int result)
  307. {
  308. if ((int)warpMode != result)
  309. {
  310. warpMode = (WarpModePreset)result;
  311. }
  312. }
  313. public enum WarpModePreset : int
  314. {
  315. TRANSLATION = 0,
  316. EUCLIDEAN,
  317. AFFINE,
  318. HOMOGRAPHY
  319. }
  320. }
  321. }