You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ImageProcessor.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using OpenCvSharp;
  5. using System.Threading.Tasks;
  6. public class ImageProcessor : MonoBehaviour
  7. {
  8. [Header("RenderTexture")]
  9. [Tooltip("RenderTexture that will be passed to the LearningBrain.")]
  10. public RenderTexture renderTextureCropped;
  11. [Header("Debug Helper")]
  12. [Tooltip("Reference to the MeshRenderer that will show the processed Image from Cozmo")]
  13. public MeshRenderer processedImageRenderer;
  14. [Tooltip("Reference to the MeshRenderer that will show the processed and cropped Image from Cozmo")]
  15. public MeshRenderer processedImageRendererCropped;
  16. /// <summary>
  17. /// Center of Gravity in the cropped canny image
  18. /// </summary>
  19. public Point CenterOfGravity { get; private set; }
  20. // OpenCVSharp parameters
  21. private Mat videoSourceImage;
  22. private Mat cannyImage;
  23. private Texture2D processedTexture;
  24. private Vec3b[] videoSourceImageData;
  25. private byte[] cannyImageData;
  26. private int imWidth = 320; // Width of the camera image from the virtual cozmo
  27. private int imHeight = 240; // Height of the camera image from the virtual cozmo
  28. private int croppedImHeight = 120; // Height of the cropped camera image from the virtual cozmo
  29. private Camera textureCamera; // Virtual Cozmo camera
  30. private Texture2D firstTexture;
  31. private void Start()
  32. {
  33. // Get reference to the cozmo camera
  34. textureCamera = GetComponent<Camera>();
  35. // Set image widths and heights based on the given RenderTextures
  36. imWidth = textureCamera.targetTexture.width;
  37. imHeight = textureCamera.targetTexture.height;
  38. //croppedImHeight = renderTextureCropped.height;
  39. //assign the processed targetTexture to the renderer to display the image
  40. processedImageRenderer.material.mainTexture = textureCamera.targetTexture;
  41. processedImageRendererCropped.material.mainTexture = renderTextureCropped;
  42. // initialize video / image with given size
  43. videoSourceImage = new Mat(imHeight, imWidth, MatType.CV_8UC3);
  44. videoSourceImageData = new Vec3b[imHeight * imWidth];
  45. cannyImage = new Mat(imHeight, imWidth, MatType.CV_8UC1);
  46. cannyImageData = new byte[croppedImHeight * imWidth];
  47. firstTexture = new Texture2D(imWidth, imHeight, TextureFormat.RGBA32, true, true);
  48. processedTexture = new Texture2D(imWidth, croppedImHeight, TextureFormat.RGBA32, true, true);
  49. }
  50. ///// <summary>
  51. ///// Gets called when a new image arrives from the camera this script lies on
  52. ///// </summary>
  53. ///// <param name="source"></param>
  54. ///// <param name="destination"></param>
  55. //private void OnRenderImage(RenderTexture source, RenderTexture destination)
  56. //{
  57. // Texture2D tex = RenderTextureToTexture2D(source);
  58. // videoSourceImage = TextureToMat(tex);
  59. // cannyImage = ProcessImage(videoSourceImage);
  60. // cannyImage = CropImage(cannyImage);
  61. // CenterOfGravityTest(cannyImage);
  62. // processedTexture = MatToTexture(cannyImage);
  63. // //processedTexture.Resize(80, 30);
  64. // //processedTexture.Apply();
  65. // //Graphics.Blit(processedTexture, destination);
  66. // Graphics.Blit(processedTexture, renderTextureCropped);
  67. //}
  68. public void ProcessRenderTexture(RenderTexture source)
  69. {
  70. ProcessRenderTexture(source, source);
  71. }
  72. public void ProcessRenderTexture(RenderTexture source, RenderTexture target)
  73. {
  74. Texture2D tex = RenderTextureToTexture2D(source);
  75. videoSourceImage = TextureToMat(tex);
  76. cannyImage = ProcessImage(videoSourceImage);
  77. cannyImage = CropImage(cannyImage);
  78. CenterOfGravityTest(cannyImage);
  79. processedTexture = MatToTexture(cannyImage);
  80. //processedTexture.Resize(80, 30);
  81. //processedTexture.Apply();
  82. //Graphics.Blit(processedTexture, destination);
  83. Graphics.Blit(processedTexture, target);
  84. }
  85. //public void ProcessRenderTexture_NEW(RenderTexture source, RenderTexture target)
  86. //{
  87. // RenderTextureToTexture2D_NEW(source);
  88. // TextureToMat_NEW(firstTexture);
  89. // ProcessImage_NEW(videoSourceImage);
  90. // cannyImage = CropImage(cannyImage);
  91. // CenterOfGravityTest(cannyImage);
  92. // MatToTexture_NEW(cannyImage);
  93. // //processedTexture.Resize(80, 30);
  94. // //processedTexture.Apply();
  95. // //Graphics.Blit(processedTexture, destination);
  96. // Graphics.Blit(processedTexture, target);
  97. //}
  98. public void OnRenderImage(RenderTexture source, RenderTexture destination)
  99. {
  100. RenderTextureToTexture2D_NEW(source);
  101. TextureToMat_NEW(firstTexture);
  102. ProcessImage_NEW(videoSourceImage);
  103. cannyImage = CropImage(cannyImage);
  104. CenterOfGravityTest(cannyImage);
  105. MatToTexture_NEW(cannyImage);
  106. Graphics.Blit(processedTexture, destination);
  107. Graphics.Blit(processedTexture, renderTextureCropped);
  108. }
  109. // Crop image to just see the middle of the original image
  110. private Mat CropImage(Mat image)
  111. {
  112. //cut a fourth out of the top and bottom of the image
  113. OpenCvSharp.Rect rectCroped = new OpenCvSharp.Rect(0, image.Height / 4, image.Width, image.Height / 2);
  114. Mat croppedImage = new Mat(image, rectCroped);
  115. return croppedImage;
  116. }
  117. //// Crop image to just see the middle of the original image
  118. //private Mat CropImage_NEW(Mat image)
  119. //{
  120. // //cut a fourth out of the top and bottom of the image
  121. // OpenCvSharp.Rect rectCroped = new OpenCvSharp.Rect(0, image.Height / 4, image.Width, image.Height / 2);
  122. // Mat croppedImage = new Mat(image, rectCroped);
  123. // return croppedImage;
  124. //}
  125. private Texture2D RenderTextureToTexture2D(RenderTexture rTex)
  126. {
  127. Texture2D tex = new Texture2D(imWidth, imHeight, TextureFormat.RGBA32, true, true);
  128. RenderTexture.active = rTex;
  129. tex.ReadPixels(new UnityEngine.Rect(0, 0, rTex.width, rTex.height), 0, 0);
  130. tex.Apply();
  131. return tex;
  132. }
  133. private void RenderTextureToTexture2D_NEW(RenderTexture rTex)
  134. {
  135. RenderTexture.active = rTex;
  136. firstTexture.ReadPixels(new UnityEngine.Rect(0, 0, rTex.width, rTex.height), 0, 0);
  137. firstTexture.Apply();
  138. }
  139. // Convert Unity Texture2D object to OpenCVSharp Mat object
  140. private Mat TextureToMat(Texture2D source)
  141. {
  142. // Color32 array : r, g, b, a
  143. Color32[] c = source.GetPixels32();
  144. // Parallel for loop
  145. // convert Color32 object to Vec3b object
  146. // Vec3b is the representation of pixel for Mat
  147. Parallel.For(0, imHeight, i =>
  148. {
  149. for (var j = 0; j < imWidth; j++)
  150. {
  151. var col = c[j + i * imWidth];
  152. var vec3 = new Vec3b
  153. {
  154. Item0 = col.b,
  155. Item1 = col.g,
  156. Item2 = col.r
  157. };
  158. // set pixel to an array
  159. videoSourceImageData[j + i * imWidth] = vec3;
  160. }
  161. });
  162. // assign the Vec3b array to Mat
  163. Mat tmpMat = new Mat(imHeight, imWidth, MatType.CV_8UC3);
  164. tmpMat.SetArray(0, 0, videoSourceImageData);
  165. return tmpMat;
  166. }
  167. // Convert Unity Texture2D object to OpenCVSharp Mat object
  168. private void TextureToMat_NEW(Texture2D source)
  169. {
  170. // Color32 array : r, g, b, a
  171. Color32[] c = source.GetPixels32();
  172. // Parallel for loop
  173. // convert Color32 object to Vec3b object
  174. // Vec3b is the representation of pixel for Mat
  175. Parallel.For(0, imHeight, i =>
  176. {
  177. for (var j = 0; j < imWidth; j++)
  178. {
  179. var col = c[j + i * imWidth];
  180. var vec3 = new Vec3b
  181. {
  182. Item0 = col.b,
  183. Item1 = col.g,
  184. Item2 = col.r
  185. };
  186. // set pixel to an array
  187. videoSourceImageData[j + i * imWidth] = vec3;
  188. }
  189. });
  190. // assign the Vec3b array to Mat
  191. videoSourceImage.SetArray(0, 0, videoSourceImageData);
  192. }
  193. // Simple example of canny edge detect
  194. private Mat ProcessImage(Mat _image)
  195. {
  196. Mat cannyImg = new Mat();
  197. Cv2.Canny(_image, cannyImg, 100, 100);
  198. return cannyImg;
  199. }
  200. // Simple example of canny edge detect
  201. private void ProcessImage_NEW(Mat _image)
  202. {
  203. Cv2.Canny(_image, cannyImage, 100, 100);
  204. }
  205. // Convert OpenCVSharp Mat object to Unity Texture2D object
  206. private Texture2D MatToTexture(Mat mat)
  207. {
  208. // cannyImageData is byte array, because canny image is grayscale
  209. mat.GetArray(0, 0, cannyImageData);
  210. // create Color32 array that can be assigned to Texture2D directly
  211. Color32[] c = new Color32[croppedImHeight * imWidth];
  212. // parallel for loop
  213. Parallel.For(0, croppedImHeight, i =>
  214. {
  215. for (var j = 0; j < imWidth; j++)
  216. {
  217. byte vec = cannyImageData[j + i * imWidth];
  218. var color32 = new Color32
  219. {
  220. r = vec,
  221. g = vec,
  222. b = vec,
  223. a = 0
  224. };
  225. c[j + i * imWidth] = color32;
  226. }
  227. });
  228. Texture2D texture = new Texture2D(imWidth, croppedImHeight, TextureFormat.RGBA32, true, true);
  229. texture.SetPixels32(c);
  230. // to update the texture, OpenGL manner
  231. texture.Apply();
  232. return texture;
  233. }
  234. // Convert OpenCVSharp Mat object to Unity Texture2D object
  235. private void MatToTexture_NEW(Mat mat)
  236. {
  237. // cannyImageData is byte array, because canny image is grayscale
  238. mat.GetArray(0, 0, cannyImageData);
  239. // create Color32 array that can be assigned to Texture2D directly
  240. Color32[] c = new Color32[croppedImHeight * imWidth];
  241. // parallel for loop
  242. Parallel.For(0, croppedImHeight, i =>
  243. {
  244. for (var j = 0; j < imWidth; j++)
  245. {
  246. byte vec = cannyImageData[j + i * imWidth];
  247. var color32 = new Color32
  248. {
  249. r = vec,
  250. g = vec,
  251. b = vec,
  252. a = 0
  253. };
  254. c[j + i * imWidth] = color32;
  255. }
  256. });
  257. processedTexture.SetPixels32(c);
  258. // to update the texture, OpenGL manner
  259. processedTexture.Apply();
  260. }
  261. private void CenterOfGravityTest(Mat processedImage)
  262. {
  263. // find moments of the image
  264. Moments m = new Moments(processedImage, true);
  265. CenterOfGravity = new Point(m.M10 / m.M00, m.M01 / m.M00);
  266. #if UNITY_EDITOR
  267. // show the image with a point mark at the centroid
  268. Cv2.Circle(processedImage, CenterOfGravity, 5, new Scalar(128, 0, 0), -1);
  269. Cv2.Flip(processedImage, processedImage, FlipMode.X);
  270. Cv2.ImShow("Image with center", processedImage);
  271. #endif
  272. }
  273. }