OpticalFlowExample.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. using UnityEngine;
  2. using UnityEngine.SceneManagement;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using OpenCVForUnity.CoreModule;
  6. using OpenCVForUnity.ImgprocModule;
  7. using OpenCVForUnity.VideoModule;
  8. using OpenCVForUnity.UnityUtils;
  9. using OpenCVForUnity.UnityUtils.Helper;
  10. namespace OpenCVForUnityExample
  11. {
  12. /// <summary>
  13. /// OpticalFlow Example
  14. /// http://stackoverflow.com/questions/6505779/android-optical-flow-with-opencv?rq=1
  15. /// http://docs.opencv.org/3.2.0/d7/d8b/tutorial_py_lucas_kanade.html
  16. /// </summary>
  17. [RequireComponent (typeof(WebCamTextureToMatHelper))]
  18. public class OpticalFlowExample : MonoBehaviour
  19. {
  20. /// <summary>
  21. /// The mat op flow this.
  22. /// </summary>
  23. Mat matOpFlowThis;
  24. /// <summary>
  25. /// The mat op flow previous.
  26. /// </summary>
  27. Mat matOpFlowPrev;
  28. /// <summary>
  29. /// The i GFFT max.
  30. /// </summary>
  31. int iGFFTMax = 40;
  32. /// <summary>
  33. /// The MO pcorners.
  34. /// </summary>
  35. MatOfPoint MOPcorners;
  36. /// <summary>
  37. /// The m MO p2fpts this.
  38. /// </summary>
  39. MatOfPoint2f mMOP2fptsThis;
  40. /// <summary>
  41. /// The m MO p2fpts previous.
  42. /// </summary>
  43. MatOfPoint2f mMOP2fptsPrev;
  44. /// <summary>
  45. /// The m MO p2fpts safe.
  46. /// </summary>
  47. MatOfPoint2f mMOP2fptsSafe;
  48. /// <summary>
  49. /// The m MOB status.
  50. /// </summary>
  51. MatOfByte mMOBStatus;
  52. /// <summary>
  53. /// The m MO ferr.
  54. /// </summary>
  55. MatOfFloat mMOFerr;
  56. /// <summary>
  57. /// The color red.
  58. /// </summary>
  59. Scalar colorRed = new Scalar (255, 0, 0, 255);
  60. /// <summary>
  61. /// The i line thickness.
  62. /// </summary>
  63. int iLineThickness = 3;
  64. /// <summary>
  65. /// The texture.
  66. /// </summary>
  67. Texture2D texture;
  68. /// <summary>
  69. /// The web cam texture to mat helper.
  70. /// </summary>
  71. WebCamTextureToMatHelper webCamTextureToMatHelper;
  72. /// <summary>
  73. /// The FPS monitor.
  74. /// </summary>
  75. FpsMonitor fpsMonitor;
  76. // Use this for initialization
  77. void Start ()
  78. {
  79. fpsMonitor = GetComponent<FpsMonitor> ();
  80. webCamTextureToMatHelper = gameObject.GetComponent<WebCamTextureToMatHelper> ();
  81. #if UNITY_ANDROID && !UNITY_EDITOR
  82. // Avoids the front camera low light issue that occurs in only some Android devices (e.g. Google Pixel, Pixel2).
  83. webCamTextureToMatHelper.avoidAndroidFrontCameraLowLightIssue = true;
  84. #endif
  85. webCamTextureToMatHelper.Initialize ();
  86. }
  87. /// <summary>
  88. /// Raises the web cam texture to mat helper initialized event.
  89. /// </summary>
  90. public void OnWebCamTextureToMatHelperInitialized ()
  91. {
  92. Debug.Log ("OnWebCamTextureToMatHelperInitialized");
  93. Mat webCamTextureMat = webCamTextureToMatHelper.GetMat ();
  94. texture = new Texture2D (webCamTextureMat.cols (), webCamTextureMat.rows (), TextureFormat.RGBA32, false);
  95. gameObject.GetComponent<Renderer> ().material.mainTexture = texture;
  96. gameObject.transform.localScale = new Vector3 (webCamTextureMat.cols (), webCamTextureMat.rows (), 1);
  97. Debug.Log ("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
  98. if (fpsMonitor != null) {
  99. fpsMonitor.Add ("width", webCamTextureMat.width ().ToString ());
  100. fpsMonitor.Add ("height", webCamTextureMat.height ().ToString ());
  101. fpsMonitor.Add ("orientation", Screen.orientation.ToString ());
  102. }
  103. float width = webCamTextureMat.width ();
  104. float height = webCamTextureMat.height ();
  105. float widthScale = (float)Screen.width / width;
  106. float heightScale = (float)Screen.height / height;
  107. if (widthScale < heightScale) {
  108. Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;
  109. } else {
  110. Camera.main.orthographicSize = height / 2;
  111. }
  112. matOpFlowThis = new Mat ();
  113. matOpFlowPrev = new Mat ();
  114. MOPcorners = new MatOfPoint ();
  115. mMOP2fptsThis = new MatOfPoint2f ();
  116. mMOP2fptsPrev = new MatOfPoint2f ();
  117. mMOP2fptsSafe = new MatOfPoint2f ();
  118. mMOBStatus = new MatOfByte ();
  119. mMOFerr = new MatOfFloat ();
  120. }
  121. /// <summary>
  122. /// Raises the web cam texture to mat helper disposed event.
  123. /// </summary>
  124. public void OnWebCamTextureToMatHelperDisposed ()
  125. {
  126. Debug.Log ("OnWebCamTextureToMatHelperDisposed");
  127. if (texture != null) {
  128. Texture2D.Destroy (texture);
  129. texture = null;
  130. }
  131. if (matOpFlowThis != null)
  132. matOpFlowThis.Dispose ();
  133. if (matOpFlowPrev != null)
  134. matOpFlowPrev.Dispose ();
  135. if (MOPcorners != null)
  136. MOPcorners.Dispose ();
  137. if (mMOP2fptsThis != null)
  138. mMOP2fptsThis.Dispose ();
  139. if (mMOP2fptsPrev != null)
  140. mMOP2fptsPrev.Dispose ();
  141. if (mMOP2fptsSafe != null)
  142. mMOP2fptsSafe.Dispose ();
  143. if (mMOBStatus != null)
  144. mMOBStatus.Dispose ();
  145. if (mMOFerr != null)
  146. mMOFerr.Dispose ();
  147. }
  148. /// <summary>
  149. /// Raises the web cam texture to mat helper error occurred event.
  150. /// </summary>
  151. /// <param name="errorCode">Error code.</param>
  152. public void OnWebCamTextureToMatHelperErrorOccurred (WebCamTextureToMatHelper.ErrorCode errorCode)
  153. {
  154. Debug.Log ("OnWebCamTextureToMatHelperErrorOccurred " + errorCode);
  155. }
  156. // Update is called once per frame
  157. void Update ()
  158. {
  159. if (webCamTextureToMatHelper.IsPlaying () && webCamTextureToMatHelper.DidUpdateThisFrame ()) {
  160. Mat rgbaMat = webCamTextureToMatHelper.GetMat ();
  161. if (mMOP2fptsPrev.rows () == 0) {
  162. // first time through the loop so we need prev and this mats
  163. // plus prev points
  164. // get this mat
  165. Imgproc.cvtColor (rgbaMat, matOpFlowThis, Imgproc.COLOR_RGBA2GRAY);
  166. // copy that to prev mat
  167. matOpFlowThis.copyTo (matOpFlowPrev);
  168. // get prev corners
  169. Imgproc.goodFeaturesToTrack (matOpFlowPrev, MOPcorners, iGFFTMax, 0.05, 20);
  170. mMOP2fptsPrev.fromArray (MOPcorners.toArray ());
  171. // get safe copy of this corners
  172. mMOP2fptsPrev.copyTo (mMOP2fptsSafe);
  173. } else {
  174. // we've been through before so
  175. // this mat is valid. Copy it to prev mat
  176. matOpFlowThis.copyTo (matOpFlowPrev);
  177. // get this mat
  178. Imgproc.cvtColor (rgbaMat, matOpFlowThis, Imgproc.COLOR_RGBA2GRAY);
  179. // get the corners for this mat
  180. Imgproc.goodFeaturesToTrack (matOpFlowThis, MOPcorners, iGFFTMax, 0.05, 20);
  181. mMOP2fptsThis.fromArray (MOPcorners.toArray ());
  182. // retrieve the corners from the prev mat
  183. // (saves calculating them again)
  184. mMOP2fptsSafe.copyTo (mMOP2fptsPrev);
  185. // and save this corners for next time through
  186. mMOP2fptsThis.copyTo (mMOP2fptsSafe);
  187. }
  188. /*
  189. Parameters:
  190. prevImg first 8-bit input image
  191. nextImg second input image
  192. prevPts vector of 2D points for which the flow needs to be found; point coordinates must be single-precision floating-point numbers.
  193. nextPts output vector of 2D points (with single-precision floating-point coordinates) containing the calculated new positions of input features in the second image; when OPTFLOW_USE_INITIAL_FLOW flag is passed, the vector must have the same size as in the input.
  194. status output status vector (of unsigned chars); each element of the vector is set to 1 if the flow for the corresponding features has been found, otherwise, it is set to 0.
  195. err output vector of errors; each element of the vector is set to an error for the corresponding feature, type of the error measure can be set in flags parameter; if the flow wasn't found then the error is not defined (use the status parameter to find such cases).
  196. */
  197. Video.calcOpticalFlowPyrLK (matOpFlowPrev, matOpFlowThis, mMOP2fptsPrev, mMOP2fptsThis, mMOBStatus, mMOFerr);
  198. if (mMOBStatus.rows () > 0) {
  199. List<Point> cornersPrev = mMOP2fptsPrev.toList ();
  200. List<Point> cornersThis = mMOP2fptsThis.toList ();
  201. List<byte> byteStatus = mMOBStatus.toList ();
  202. int x = 0;
  203. int y = byteStatus.Count - 1;
  204. for (x = 0; x < y; x++) {
  205. if (byteStatus [x] == 1) {
  206. Point pt = cornersThis [x];
  207. Point pt2 = cornersPrev [x];
  208. Imgproc.circle (rgbaMat, pt, 5, colorRed, iLineThickness - 1);
  209. Imgproc.line (rgbaMat, pt, pt2, colorRed, iLineThickness);
  210. }
  211. }
  212. }
  213. // 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);
  214. Utils.fastMatToTexture2D (rgbaMat, texture);
  215. }
  216. }
  217. /// <summary>
  218. /// Raises the destroy event.
  219. /// </summary>
  220. void OnDestroy ()
  221. {
  222. webCamTextureToMatHelper.Dispose ();
  223. }
  224. /// <summary>
  225. /// Raises the back button click event.
  226. /// </summary>
  227. public void OnBackButtonClick ()
  228. {
  229. SceneManager.LoadScene ("OpenCVForUnityExample");
  230. }
  231. /// <summary>
  232. /// Raises the play button click event.
  233. /// </summary>
  234. public void OnPlayButtonClick ()
  235. {
  236. webCamTextureToMatHelper.Play ();
  237. }
  238. /// <summary>
  239. /// Raises the pause button click event.
  240. /// </summary>
  241. public void OnPauseButtonClick ()
  242. {
  243. webCamTextureToMatHelper.Pause ();
  244. }
  245. /// <summary>
  246. /// Raises the stop button click event.
  247. /// </summary>
  248. public void OnStopButtonClick ()
  249. {
  250. webCamTextureToMatHelper.Stop ();
  251. }
  252. /// <summary>
  253. /// Raises the change camera button click event.
  254. /// </summary>
  255. public void OnChangeCameraButtonClick ()
  256. {
  257. webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.IsFrontFacing ();
  258. }
  259. }
  260. }