BarcodeDetectorWebCamExample.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #if !UNITY_WSA_10_0
  2. using OpenCVForUnity.CoreModule;
  3. using OpenCVForUnity.ImgprocModule;
  4. using OpenCVForUnity.ObjdetectModule;
  5. using OpenCVForUnity.UnityUtils;
  6. using OpenCVForUnity.UnityUtils.Helper;
  7. using System.Collections.Generic;
  8. using UnityEngine;
  9. using UnityEngine.SceneManagement;
  10. using Random = UnityEngine.Random;
  11. namespace OpenCVForUnityExample
  12. {
  13. /// <summary>
  14. /// BarcodeDetector WebCam Example
  15. /// An example of detecting Barcode in a image of WebCamTexture using the BarcodeDetector class.
  16. /// https://github.com/opencv/opencv_contrib/blob/master/modules/barcode/samples/barcode.cpp
  17. /// </summary>
  18. [RequireComponent(typeof(WebCamTextureToMatHelper))]
  19. public class BarcodeDetectorWebCamExample : MonoBehaviour
  20. {
  21. /// <summary>
  22. /// The texture.
  23. /// </summary>
  24. Texture2D texture;
  25. /// <summary>
  26. /// The BarcodeDetector detector.
  27. /// </summary>
  28. BarcodeDetector detector;
  29. /// <summary>
  30. /// The webcam texture to mat helper.
  31. /// </summary>
  32. WebCamTextureToMatHelper webCamTextureToMatHelper;
  33. /// <summary>
  34. /// The FPS monitor.
  35. /// </summary>
  36. FpsMonitor fpsMonitor;
  37. // Use this for initialization
  38. void Start()
  39. {
  40. fpsMonitor = GetComponent<FpsMonitor>();
  41. webCamTextureToMatHelper = gameObject.GetComponent<WebCamTextureToMatHelper>();
  42. detector = new BarcodeDetector();
  43. // When using super resolution.
  44. // Please, download 'sr.*' from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode and put them into the StreamingAssets/OpenCVForUnity/barcode directory.
  45. //detector = new BarcodeDetector(Utils.getFilePath("OpenCVForUnity/barcode/sr.prototxt"), Utils.getFilePath("OpenCVForUnity/barcode/sr.caffemodel"));
  46. #if UNITY_ANDROID && !UNITY_EDITOR
  47. // Avoids the front camera low light issue that occurs in only some Android devices (e.g. Google Pixel, Pixel2).
  48. webCamTextureToMatHelper.avoidAndroidFrontCameraLowLightIssue = true;
  49. #endif
  50. webCamTextureToMatHelper.Initialize();
  51. }
  52. /// <summary>
  53. /// Raises the web cam texture to mat helper initialized event.
  54. /// </summary>
  55. public void OnWebCamTextureToMatHelperInitialized()
  56. {
  57. Debug.Log("OnWebCamTextureToMatHelperInitialized");
  58. Mat webCamTextureMat = webCamTextureToMatHelper.GetMat();
  59. texture = new Texture2D(webCamTextureMat.cols(), webCamTextureMat.rows(), TextureFormat.RGBA32, false);
  60. Utils.matToTexture2D(webCamTextureMat, texture);
  61. gameObject.GetComponent<Renderer>().material.mainTexture = texture;
  62. gameObject.transform.localScale = new Vector3(webCamTextureMat.cols(), webCamTextureMat.rows(), 1);
  63. Debug.Log("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
  64. if (fpsMonitor != null)
  65. {
  66. fpsMonitor.Add("width", webCamTextureMat.width().ToString());
  67. fpsMonitor.Add("height", webCamTextureMat.height().ToString());
  68. fpsMonitor.Add("orientation", Screen.orientation.ToString());
  69. }
  70. float width = webCamTextureMat.width();
  71. float height = webCamTextureMat.height();
  72. float widthScale = (float)Screen.width / width;
  73. float heightScale = (float)Screen.height / height;
  74. if (widthScale < heightScale)
  75. {
  76. Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;
  77. }
  78. else
  79. {
  80. Camera.main.orthographicSize = height / 2;
  81. }
  82. // If the WebCam is front facing, flip the Mat horizontally. Required for successful detection of Barcode.
  83. if (webCamTextureToMatHelper.IsFrontFacing() && !webCamTextureToMatHelper.flipHorizontal)
  84. {
  85. webCamTextureToMatHelper.flipHorizontal = true;
  86. }
  87. else if (!webCamTextureToMatHelper.IsFrontFacing() && webCamTextureToMatHelper.flipHorizontal)
  88. {
  89. webCamTextureToMatHelper.flipHorizontal = false;
  90. }
  91. }
  92. /// <summary>
  93. /// Raises the web cam texture to mat helper disposed event.
  94. /// </summary>
  95. public void OnWebCamTextureToMatHelperDisposed()
  96. {
  97. Debug.Log("OnWebCamTextureToMatHelperDisposed");
  98. if (texture != null)
  99. {
  100. Texture2D.Destroy(texture);
  101. texture = null;
  102. }
  103. }
  104. /// <summary>
  105. /// Raises the web cam texture to mat helper error occurred event.
  106. /// </summary>
  107. /// <param name="errorCode">Error code.</param>
  108. public void OnWebCamTextureToMatHelperErrorOccurred(WebCamTextureToMatHelper.ErrorCode errorCode)
  109. {
  110. Debug.Log("OnWebCamTextureToMatHelperErrorOccurred " + errorCode);
  111. }
  112. // Update is called once per frame
  113. void Update()
  114. {
  115. if (webCamTextureToMatHelper.IsPlaying() && webCamTextureToMatHelper.DidUpdateThisFrame())
  116. {
  117. Mat rgbaMat = webCamTextureToMatHelper.GetMat();
  118. List<string> decoded_info = new List<string>();
  119. List<string> decoded_type = new List<string>();
  120. Mat corners = new Mat();
  121. bool result_detection = detector.detectAndDecodeWithType(rgbaMat, decoded_info, decoded_type, corners);
  122. // draw Barcode contours.
  123. if (result_detection)
  124. DrawBarcodeResults(rgbaMat, corners, decoded_info, decoded_type);
  125. corners.Dispose();
  126. Utils.matToTexture2D(rgbaMat, texture);
  127. }
  128. }
  129. private void DrawBarcodeResults(Mat frame, Mat corners, List<string> decoded_info, List<string> decoded_type)
  130. {
  131. if (!corners.empty())
  132. {
  133. using (Mat corners_32S = new Mat())
  134. {
  135. corners.convertTo(corners_32S, CvType.CV_32SC2);
  136. for (int i = 0; i < corners_32S.rows(); i++)
  137. {
  138. using (Mat cornersMat_row = corners_32S.row(i))
  139. using (MatOfPoint cornersMat = new MatOfPoint(cornersMat_row.reshape(2, 4)))
  140. {
  141. if (decoded_info.Count > i)
  142. {
  143. DrawBarcodeContour(frame, cornersMat, decoded_info[i], decoded_type[i]);
  144. }
  145. else
  146. {
  147. DrawBarcodeContour(frame, cornersMat);
  148. }
  149. }
  150. if (decoded_info.Count > i)
  151. {
  152. if (!string.IsNullOrEmpty(decoded_info[i]))
  153. {
  154. Debug.Log("TYPE: " + decoded_type[i] + " INFO: " + decoded_info[i]);
  155. }
  156. else
  157. {
  158. Debug.Log("can't decode 1D barcode");
  159. }
  160. }
  161. else
  162. {
  163. Debug.Log("decode information is not available (disabled)");
  164. }
  165. }
  166. }
  167. }
  168. else
  169. {
  170. Debug.Log("Barcode is not detected");
  171. }
  172. }
  173. private void DrawBarcodeContour(Mat color_image, MatOfPoint corners, string decoded_info = "", string decoded_type = "")
  174. {
  175. if (!corners.empty())
  176. {
  177. bool decodable = decoded_type != "";
  178. double show_radius = (color_image.rows() > color_image.cols()) ? (2.813 * color_image.rows()) / color_image.cols() : (2.813 * color_image.cols()) / color_image.rows();
  179. double contour_radius = show_radius * 0.4;
  180. List<MatOfPoint> barcode_contours = new List<MatOfPoint>();
  181. barcode_contours.Add(corners);
  182. Imgproc.drawContours(color_image, barcode_contours, 0, decodable ? new Scalar(0, 255, 0, 255) : new Scalar(255, 0, 0, 255), Mathf.RoundToInt((float)contour_radius));
  183. int[] p = new int[8];
  184. corners.get(0, 0, p);
  185. Imgproc.putText(color_image, decoded_info, new Point(p[0] + 5, p[1] - 25), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255, 255), 2, Imgproc.LINE_AA, false);
  186. Imgproc.putText(color_image, decoded_type, new Point(p[0] + 5, p[1] - 5), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255, 255), 2, Imgproc.LINE_AA, false);
  187. for (int i = 0; i < 8; i = i + 2)
  188. {
  189. Scalar color = new Scalar(Random.Range(0, 255), Random.Range(0, 255), Random.Range(0, 255), 255);
  190. Imgproc.circle(color_image, new Point(p[i], p[i + 1]), Mathf.RoundToInt((float)contour_radius), color, -1);
  191. }
  192. }
  193. }
  194. /// <summary>
  195. /// Raises the destroy event.
  196. /// </summary>
  197. void OnDestroy()
  198. {
  199. webCamTextureToMatHelper.Dispose();
  200. if (detector != null)
  201. detector.Dispose();
  202. }
  203. /// <summary>
  204. /// Raises the back button click event.
  205. /// </summary>
  206. public void OnBackButtonClick()
  207. {
  208. SceneManager.LoadScene("OpenCVForUnityExample");
  209. }
  210. /// <summary>
  211. /// Raises the play button click event.
  212. /// </summary>
  213. public void OnPlayButtonClick()
  214. {
  215. webCamTextureToMatHelper.Play();
  216. }
  217. /// <summary>
  218. /// Raises the pause button click event.
  219. /// </summary>
  220. public void OnPauseButtonClick()
  221. {
  222. webCamTextureToMatHelper.Pause();
  223. }
  224. /// <summary>
  225. /// Raises the stop button click event.
  226. /// </summary>
  227. public void OnStopButtonClick()
  228. {
  229. webCamTextureToMatHelper.Stop();
  230. }
  231. /// <summary>
  232. /// Raises the change camera button click event.
  233. /// </summary>
  234. public void OnChangeCameraButtonClick()
  235. {
  236. webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.requestedIsFrontFacing;
  237. }
  238. }
  239. }
  240. #endif